Zulip Chat Archive
Stream: lean4
Topic: include lean.h
Floris van Doorn (Dec 14 2021 at 12:00):
Another stupid question: How do I compile and run code? I can compile a file using lake env lean ... -c ...
.
If I just stupidly compile this C file, I get an error that lean/lean.h
is not found (at line 4: #include <lean/lean.h>
).
How do I compile this C file correctly?
Henrik Böving (Dec 14 2021 at 12:02):
There is an FFI example over here https://github.com/leanprover/lake/blob/master/examples/ffi/lakefile.lean that shows how to marry C and Lean 4 code.
Floris van Doorn (Dec 14 2021 at 12:14):
I see, that is useful. Can I somehow use this to compile tactics/programs from a single file in the mathlib4
repository (which, by default doesn't compile its files)?
Arthur Paulino (Dec 14 2021 at 12:15):
@Floris van Doorn more specifically, this part tells the compiler where the lean/lean.h
header is:
#["-I", (← getLeanIncludeDir).toString]
Arthur Paulino (Dec 14 2021 at 12:33):
Floris van Doorn said:
I see, that is useful. Can I somehow use this to compile tactics/programs from a single file in the
mathlib4
repository (which, by default doesn't compile its files)?
What do you mean? Do you want to define a function in Mathlib4 that runs C code?
Sebastian Ullrich (Dec 14 2021 at 12:58):
@Floris van Doorn AFAIK, Lake can only build a single library or executable per package right now. But you can change binRoot
to temporarily point at an appropriate module and then use lake build :bin
.
Floris van Doorn (Dec 14 2021 at 13:14):
Ok, let me take a step back.
I am trying to collect all declarations in the environment and do some operations on them. When doing this with #eval
inside Lean, these operations are starting to become really expensive, and I was wondering if using compiled code instead of interpreted code would help here.
So if I understand the comments correctly, I now have to write a function
def main (strs : List String) : IO UInt32 := ...
then use lake build
with the appropriate configuration to run the code after compiling it?
Or can I do the compilation from Lean itself (using compileO
?)
Also, how do I pass (data computed from) the current environment to the compiled function (if the function I compile lives in IO
)?
Gabriel Ebner (Dec 14 2021 at 13:29):
What operations are you trying to do? The interpreter isn't that slow, and mathlib4+lean is pretty small.
Patrick Massot (Dec 14 2021 at 13:35):
Maybe he is operating on binport output?
Floris van Doorn (Dec 14 2021 at 13:37):
I was also a bit surprised that it would already slow down. I might have some inefficient code.
I'm trying to do a kind of page rank on the declarations. So it mostly involves mapping functions over arrays and Float
operations.
Floris van Doorn (Dec 14 2021 at 13:37):
I am currently just doing it on mathlib4+Lean, but the idea is to later do it on the binport output. Unfortunately the former is already slow.
Floris van Doorn (Dec 14 2021 at 13:40):
The (very messy) file is here: https://github.com/leanprover-community/mathlib4/blob/fpvandoorn/graph/Personal/Graph.lean
Sebastian Ullrich (Dec 14 2021 at 13:40):
If you're on Linux, you can get a rough idea of what it is spending time on by running perf top
in parallel
Floris van Doorn (Dec 14 2021 at 13:46):
A majority of the computation time seems to be spent on a quicksort:
def sortRevByWeight (g : Array NameNode) : Array NameNode :=
g.qsort λ nn1 nn2 => nn1.weight > nn2.weight
Here nni.weight
are Float
s
Floris van Doorn (Dec 14 2021 at 13:48):
and the array is about 27k entries long.
Sebastian Ullrich (Dec 14 2021 at 13:50):
Ah, makes sense. qsort
will be specialized to the comparison function, so it cannot use any precompiled version. And LLVM will make a much better job of the resulting code than the interpreter.
Floris van Doorn (Dec 14 2021 at 13:52):
If interesting, these are the top entries of sudo perf top
18.93% libleanshared.so [.] lean_inc_ref_cold
18.42% libleanshared.so [.] lean_dec_ref_cold
11.17% libleanshared.so [.] lean::ir::interpreter::eval_body
11.14% libleanshared.so [.] lean::rb_map<lean::name, lean::ir::interpreter::symbol_cache_entry, lean::name_quick_cmp>::find
9.00% libleanshared.so [.] lean::ir::interpreter::call
7.86% libleanshared.so [.] lean_name_eq
3.53% libleanshared.so [.] lean_inc
3.04% libleanshared.so [.] lean::ir::interpreter::pop_frame
2.72% libleanshared.so [.] lean::ir::interpreter::lookup_symbol
2.36% libleanshared.so [.] lean::ir::interpreter::eval_expr
2.28% libleanshared.so [.] lean::ir::interpreter::stub_m
1.06% libleanshared.so [.] std::__1::vector<lean::ir::value, std::__1::allocator<lean::ir::value> >::__append
0.85% libleanshared.so [.] lean::ir::interpreter::stub_m_aux
0.71% libleanshared.so [.] lean::mk_pair<lean::name, lean::ir::interpreter::symbol_cache_entry>
0.52% libleanshared.so [.] lean::rb_map<lean::name, lean::ir::interpreter::constant_cache_entry, lean::name_quick_cmp>::find
Sebastian Ullrich (Dec 14 2021 at 13:52):
That definitely looks like the interpreter :)
Sebastian Ullrich (Dec 14 2021 at 13:52):
Floris van Doorn said:
So if I understand the comments correctly, I now have to write a function
def main (strs : List String) : IO UInt32 := ...
then uselake build
with the appropriate configuration to run the code after compiling it?
Yes, I think that is the simplest way currently.
Also, how do I pass (data computed from) the current environment to the compiled function (if the function I compile lives in
IO
)?
You can't directly. You can get an Environment
in the compiled program by running importModules
, in which case you should run the binary inside lake env
so that LEAN_PATH
is set correctly.
Henrik Böving (Dec 14 2021 at 13:54):
I implemented this over here: https://github.com/hargoniX/doc-gen4/blob/main/DocGen4/Load.lean if you want some place you can copy paste from :P (its largely adapted from the compiler and language server though)
Floris van Doorn (Dec 14 2021 at 13:58):
Sebastian Ullrich said:
You can't directly. You can get an
Environment
in the compiled program by runningimportModules
, in which case you should run the binary insidelake env
so thatLEAN_PATH
is set correctly.
Thanks! So something like this?
def main (strs : List String) : IO UInt32 := do
let env ← importModules [{module := `Mathlib}] {}
let u ← EIO.toIO (λ _ => "error") (CoreM.run' test {} {env := env})
return 0
Floris van Doorn (Dec 14 2021 at 13:59):
Henrik Böving said:
I implemented this over here: https://github.com/hargoniX/doc-gen4/blob/main/DocGen4/Load.lean if you want some place you can copy paste from :P (its largely adapted from the compiler and language server though)
Thanks, I'll take a look
Sebastian Ullrich (Dec 14 2021 at 14:06):
Ah, you also need to run
initSearchPath (← Lean.findSysroot?) ["build/lib"]
before importModules
. Then you don't even need lake env
if you run the executable from the project root.
Floris van Doorn (Dec 14 2021 at 16:00):
@Sebastian Ullrich I think I'm getting closer. I now have the following files:
-- Mathlib/Graph.lean
[...]
def main (strs : List String) : IO UInt32 := do
initSearchPath (← Lean.findSysroot?) ["build/lib"]
let env ← importModules [{module := `Mathlib}] {}
let u ← CoreM.toIO test {} {env := env}
return 0
and
-- lakefile.lean
import Lake
open Lake DSL
package mathlib { binRoot := `Mathlib.Graph }
I can compile the file fine with lake build
. However, running ./build/bin/mathlib
gives me
uncaught exception: could not find native implementation of external declaration 'UInt64.ofNatCore' (symbols 'l_UInt64_ofNatCore___boxed' or 'l_UInt64_ofNatCore')
Searching on Zulip gives me similar errors using leanpkg
where the solution is to add the option LINK_OPTS=-rdynamic
. Do I have to do something similar with lake
?
Sebastian Ullrich (Dec 14 2021 at 16:02):
Ah, you can use supportInterpreter := true
in the lakefile for that
Arthur Paulino (Dec 14 2021 at 16:02):
@Floris van Doorn This helped me when I got that error:
add supportInterpreter := true
to the package in the lakefile
Floris van Doorn (Dec 14 2021 at 16:06):
Thanks, that works!
Floris van Doorn (Dec 14 2021 at 16:11):
The qsort
which was the bottleneck when interpreted is ~100 times faster now :-)
Last updated: Dec 20 2023 at 11:08 UTC