Zulip Chat Archive

Stream: lean4

Topic: Stack overflow when enumerating a matrix


Sofia (Nov 06 2021 at 08:45):

Hello world. Can you increase the stack size?

Stack overflow detected. Aborting.

Alternatively is there a better way to initialize an array/matrix over a function of its coordinates which does not lead to exhausting the stack?

List.range height
|> List.map (fun y => List.range width |> List.map (f . y))
|> List.join
|> List.map Nat.toUInt8
|> List.toArray
|> ByteArray.mk

Sofia (Nov 06 2021 at 08:46):

I'm trying to render images. 144p works, but any higher 16:9 resolution exceeds the limit.

Huỳnh Trần Khanh (Nov 06 2021 at 08:47):

run ulimit -s unlimited before running your program

Huỳnh Trần Khanh (Nov 06 2021 at 08:47):

that is if you're on linux

Sebastian Ullrich (Nov 06 2021 at 08:48):

Allocating a/multiple cons cells per pixel doesn't sound very efficient to begin with. You should create the array using ByteArray.mkEmpty <size> and then manipulate it using ByteArray.set!.

Sofia (Nov 06 2021 at 08:49):

Aye, thanks.

Sebastian Ullrich (Nov 06 2021 at 08:50):

It's not as nicely functional as your version, but should be vastly more efficient

Sofia (Nov 06 2021 at 08:50):

Can make it functional. ;)

Sofia (Nov 06 2021 at 08:51):

Thanks for the suggestion. Either way I'll abstract around it because this really should just be its own function on the (Byte)Array types IMHO. Lean 3 has Steam.approx to construct lists from functions. Not quite sure how the Lean 4 streams work, but did note no approx function.

Sofia (Nov 06 2021 at 09:13):

Doesn't need to be super functional anyway. At least an excuse to use parallel for-in-do.

def bytearray_from_matrix (width height : Nat) (f : Nat -> Nat -> Nat) : ByteArray := do
    let mut res := ByteArray.mkEmpty (height * width)
    for x in List.range width, y in List.range height do
        res := res.set! (y * width + x) (f x y |> Nat.toUInt8)
    res

Sofia (Nov 06 2021 at 09:14):

Next question: is either Lean 4 or C smart enough to optimize away that multiplication. I sure hope so. But don't quite know the behavior of the parallel for loop here. Any insight?

Sofia (Nov 06 2021 at 09:15):

Specifically the order of its iteration.

Sofia (Nov 06 2021 at 09:18):

Can confirm it behaves better with the stack.

Sofia (Nov 06 2021 at 09:21):

Uhh... My array is empty. o.o

Sofia (Nov 06 2021 at 09:23):

Seems set fails. Pushing makes more sense anyway.

let mut res := ByteArray.mkEmpty (height * width)
for y in List.range height do
    for x in List.range width do
        res := res.push (f x y |> Nat.toUInt8)
res

Sebastian Ullrich (Nov 06 2021 at 09:24):

Yeah, my bad

Sofia (Nov 06 2021 at 09:26):

Now able to render 1920x1080x24bpp. :)

Sofia (Nov 06 2021 at 09:27):

Only ~6MiB when encoded as PPM or PAM. Heh.

Sofia (Nov 06 2021 at 09:30):

Maybe FFI to https://docs.rs/png next. ;-)

Know of any Rust + Lean 4 FFI examples?

Sebastian Ullrich (Nov 06 2021 at 09:36):

@Joe Hendrix has been investigating that route, but there is no practicable solution yet afaik. The C ABI is the only somewhat supported FFI so far.

Sofia (Nov 06 2021 at 09:38):

Fortunately at least for now; I only need to call from Lean to Rust via C, so... I hope not too painful.

Sebastian Ullrich (Nov 06 2021 at 09:46):

See https://leanprover.github.io/lean4/doc/dev/ffi.html for the current state

Sofia (Nov 06 2021 at 09:53):

Aye, I've seen this doc. Thanks though. :)

Joe Hendrix (Nov 06 2021 at 15:26):

I've haven't devoted much time to it in the last few months due to changing jobs, but I have a Rust package that I call from Lean here.

Sofia (Nov 06 2021 at 16:03):

Neat. Will certainly have to play with this. :)


Last updated: Dec 20 2023 at 11:08 UTC