lean-interact 0.9.2__tar.gz → 0.10.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. {lean_interact-0.9.2 → lean_interact-0.10.0}/PKG-INFO +2 -2
  2. {lean_interact-0.9.2 → lean_interact-0.10.0}/README.md +1 -1
  3. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/api/sessioncache.md +4 -0
  4. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/index.md +1 -1
  5. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/user-guide/examples.md +2 -2
  6. lean_interact-0.10.0/docs/user-guide/performance.md +224 -0
  7. {lean_interact-0.9.2 → lean_interact-0.10.0}/examples/beq_plus.py +24 -8
  8. lean_interact-0.10.0/examples/parallelization.py +125 -0
  9. {lean_interact-0.9.2 → lean_interact-0.10.0}/pyproject.toml +1 -1
  10. {lean_interact-0.9.2 → lean_interact-0.10.0}/src/lean_interact/__init__.py +3 -0
  11. {lean_interact-0.9.2 → lean_interact-0.10.0}/src/lean_interact/server.py +7 -7
  12. lean_interact-0.10.0/src/lean_interact/sessioncache.py +447 -0
  13. {lean_interact-0.9.2 → lean_interact-0.10.0}/src/lean_interact/utils.py +1 -1
  14. {lean_interact-0.9.2 → lean_interact-0.10.0}/tests/test_server.py +195 -17
  15. lean_interact-0.9.2/docs/user-guide/performance.md +0 -199
  16. lean_interact-0.9.2/examples/multi_processing.py +0 -60
  17. lean_interact-0.9.2/src/lean_interact/sessioncache.py +0 -235
  18. {lean_interact-0.9.2 → lean_interact-0.10.0}/.devcontainer/devcontainer.json +0 -0
  19. {lean_interact-0.9.2 → lean_interact-0.10.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  20. {lean_interact-0.9.2 → lean_interact-0.10.0}/.github/copilot-instructions.md +0 -0
  21. {lean_interact-0.9.2 → lean_interact-0.10.0}/.github/workflows/ci.yml +0 -0
  22. {lean_interact-0.9.2 → lean_interact-0.10.0}/.github/workflows/docs.yml +0 -0
  23. {lean_interact-0.9.2 → lean_interact-0.10.0}/.github/workflows/publish-to-pypi.yml +0 -0
  24. {lean_interact-0.9.2 → lean_interact-0.10.0}/.gitignore +0 -0
  25. {lean_interact-0.9.2 → lean_interact-0.10.0}/LICENSE +0 -0
  26. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/.nojekyll +0 -0
  27. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/api/config.md +0 -0
  28. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/api/interface.md +0 -0
  29. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/api/project.md +0 -0
  30. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/api/server.md +0 -0
  31. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/api/utils.md +0 -0
  32. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/contributing.md +0 -0
  33. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/generate_changelog.py +0 -0
  34. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/theme/main.html +0 -0
  35. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/user-guide/basic-usage.md +0 -0
  36. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/user-guide/custom-lean-configuration.md +0 -0
  37. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/user-guide/data-extraction.md +0 -0
  38. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/user-guide/getting-started.md +0 -0
  39. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/user-guide/installation.md +0 -0
  40. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/user-guide/set-options.md +0 -0
  41. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/user-guide/tactic-mode.md +0 -0
  42. {lean_interact-0.9.2 → lean_interact-0.10.0}/docs/user-guide/troubleshooting.md +0 -0
  43. {lean_interact-0.9.2 → lean_interact-0.10.0}/examples/extract_mathlib_decls.py +0 -0
  44. {lean_interact-0.9.2 → lean_interact-0.10.0}/examples/proof_generation_and_autoformalization.py +0 -0
  45. {lean_interact-0.9.2 → lean_interact-0.10.0}/examples/type_check.py +0 -0
  46. {lean_interact-0.9.2 → lean_interact-0.10.0}/mkdocs.yml +0 -0
  47. {lean_interact-0.9.2 → lean_interact-0.10.0}/src/lean_interact/config.py +0 -0
  48. {lean_interact-0.9.2 → lean_interact-0.10.0}/src/lean_interact/interface.py +0 -0
  49. {lean_interact-0.9.2 → lean_interact-0.10.0}/src/lean_interact/project.py +0 -0
  50. {lean_interact-0.9.2 → lean_interact-0.10.0}/src/lean_interact/py.typed +0 -0
  51. {lean_interact-0.9.2 → lean_interact-0.10.0}/tests/test_concurrency.py +0 -0
  52. {lean_interact-0.9.2 → lean_interact-0.10.0}/tests/test_git_functionality.py +0 -0
  53. {lean_interact-0.9.2 → lean_interact-0.10.0}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lean-interact
3
- Version: 0.9.2
3
+ Version: 0.10.0
4
4
  Summary: LeanInteract is a Python package that allows you to interact with the Lean theorem prover.
5
5
  Author-email: Auguste Poiroux <auguste.poiroux@epfl.ch>
6
6
  License: MIT License
@@ -53,7 +53,7 @@ Check the [documentation](https://augustepoiroux.github.io/LeanInteract/) for de
53
53
  - **🔗 Interactivity**: Execute Lean code and files directly from Python.
54
54
  - **🚀 Ease of Use**: LeanInteract abstracts the complexities of Lean setup and interaction.
55
55
  - **💻 Cross-platform**: Works on Windows, macOS, and Linux operating systems.
56
- - **🔧 Compatibility**: Supports all Lean versions between `v4.8.0-rc1` and `v4.25.0-rc2`.
56
+ - **🔧 Compatibility**: Supports all Lean versions between `v4.8.0-rc1` and `v4.25.1`.
57
57
  - We backport the latest features of Lean REPL to older versions of Lean (see [fork](https://github.com/augustepoiroux/repl)).
58
58
  - **📦 Temporary Projects**: Easily instantiate temporary Lean environments.
59
59
  - Useful for experimenting with benchmarks depending on [Mathlib](https://github.com/leanprover-community/mathlib4) like [ProofNet#](https://huggingface.co/datasets/PAug/ProofNetSharp) and [MiniF2F](https://github.com/yangky11/miniF2F-lean4).
@@ -15,7 +15,7 @@ Check the [documentation](https://augustepoiroux.github.io/LeanInteract/) for de
15
15
  - **🔗 Interactivity**: Execute Lean code and files directly from Python.
16
16
  - **🚀 Ease of Use**: LeanInteract abstracts the complexities of Lean setup and interaction.
17
17
  - **💻 Cross-platform**: Works on Windows, macOS, and Linux operating systems.
18
- - **🔧 Compatibility**: Supports all Lean versions between `v4.8.0-rc1` and `v4.25.0-rc2`.
18
+ - **🔧 Compatibility**: Supports all Lean versions between `v4.8.0-rc1` and `v4.25.1`.
19
19
  - We backport the latest features of Lean REPL to older versions of Lean (see [fork](https://github.com/augustepoiroux/repl)).
20
20
  - **📦 Temporary Projects**: Easily instantiate temporary Lean environments.
21
21
  - Useful for experimenting with benchmarks depending on [Mathlib](https://github.com/leanprover-community/mathlib4) like [ProofNet#](https://huggingface.co/datasets/PAug/ProofNetSharp) and [MiniF2F](https://github.com/yangky11/miniF2F-lean4).
@@ -1,9 +1,13 @@
1
+ # Session Cache API
2
+
1
3
  ::: lean_interact.sessioncache
2
4
  options:
3
5
  heading_level: 1
4
6
  heading: "Session Cache"
5
7
  show_symbol_type_heading: false
6
8
  members:
9
+ - ReplaySessionCache
7
10
  - PickleSessionCache
8
11
  - SessionState
12
+ - ReplaySessionState
9
13
  - PickleSessionState
@@ -17,7 +17,7 @@ hide:
17
17
  - **🔗 Interactivity**: Execute Lean code and files directly from Python
18
18
  - **🚀 Ease of Use**: LeanInteract abstracts the complexities of Lean setup and interaction
19
19
  - **💻 Cross-platform**: Works on Windows, macOS, and Linux operating systems
20
- - **🔧 Compatibility**: Supports all Lean versions between `v4.8.0-rc1` and `v4.25.0-rc2`
20
+ - **🔧 Compatibility**: Supports all Lean versions between `v4.8.0-rc1` and `v4.25.1`
21
21
  - We backport the latest features of Lean REPL to older versions of Lean (see [fork](https://github.com/augustepoiroux/repl)).
22
22
  - **📦 Temporary Projects**: Easily instantiate temporary Lean environments
23
23
  - Useful for experimenting with benchmarks depending on [Mathlib](https://github.com/leanprover-community/mathlib4) like [ProofNet#](https://huggingface.co/datasets/PAug/ProofNetSharp) and [MiniF2F](https://github.com/yangky11/miniF2F-lean4)
@@ -73,8 +73,8 @@ print(result) # Example raw output from the REPL
73
73
 
74
74
  For more comprehensive examples, check out the following scripts in the examples directory:
75
75
 
76
- 1. [**multi_processing.py**](https://github.com/augustepoiroux/LeanInteract/blob/main/examples/multi_processing.py)
77
- Shows how to use multiprocessing with LeanInteract for parallel proof checking.
76
+ 1. [**parallelization.py**](https://github.com/augustepoiroux/LeanInteract/blob/main/examples/parallelization.py)
77
+ Shows how to parallelize calls to LeanInteract for faster processing.
78
78
 
79
79
  2. [**proof_generation_and_autoformalization.py**](https://github.com/augustepoiroux/LeanInteract/blob/main/examples/proof_generation_and_autoformalization.py)
80
80
  Shows how to use models like DeepSeek-Prover-V1.5 and Goedel-Prover on MiniF2F and ProofNet# benchmarks.
@@ -0,0 +1,224 @@
1
+ # Performance & Parallelization
2
+
3
+ LeanInteract provides **three complementary performance layers** that can be combined:
4
+
5
+ 1. **Within-command speedups (inside a single Lean request)**
6
+ - **Incremental elaboration**: reuse previous elaboration results instead of starting from scratch.
7
+ - **Parallel elaboration**: use `Elab.async` so Lean elaborates independent parts in parallel.
8
+ 2. **Across-command speedups (multiple commands / tasks)**
9
+ - **External parallelization**: run several Lean servers in parallel, typically via `AutoLeanServer`.
10
+
11
+ All three can be enabled together for maximum throughput: fast single commands (incremental + parallel elaboration) and high aggregate throughput across many commands (external parallelization).
12
+ By default, **incremental elaboration** and **parallel elaboration** are enabled in `LeanREPLConfig`. **External parallelization** can be implemented in various ways, thus no default is provided.
13
+
14
+ ## Incremental Elaboration
15
+
16
+ Incremental elaboration is a free performance boost that reduces latency and memory by automatically reusing elaboration results from prior commands executed on the same `LeanServer`.
17
+
18
+ ### How it works
19
+
20
+ In Lean, incremental elaboration allows reusing the elaboration state of a prior command when elaborating a new command that shares a common prefix.
21
+ For example, if you have already elaborated:
22
+
23
+ ```lean
24
+ import Mathlib
25
+ def foo : Nat := 42
26
+ ```
27
+
28
+ and now want to elaborate:
29
+
30
+ ```lean
31
+ import Mathlib
32
+ def bar : Nat := 56
33
+ ```
34
+
35
+ then Lean can reuse the elaboration state after `import Mathlib` from the first command instead of starting from scratch, effectively loading Mathlib only once.
36
+
37
+ Incremental elaboration therefore **automatically finds the best incremental state from the previous command** to reuse for the new command. For VS Code users, this corresponds to how Lean4's built-in language server reuses elaboration states when editing files (vertical orange loading bar in the gutter).
38
+
39
+ LeanInteract generalizes this mechanism further by extending the search for the best incremental state to reuse to **all prior commands** in the history, not just the most recent one. The optimal incremental state is found using a Trie-based data structure, which in practice has no noticeable overhead in both memory and CPU usage.
40
+
41
+ ### Properties
42
+
43
+ - Write commands in any order without manually worrying about managing command states.
44
+ - The Trie-based history lookup ensures that the best reuse point is found efficiently, independent of the number of prior commands.
45
+ - In the worst case, memory and CPU usage will be similar to non-incremental elaboration (if no reuse is possible).
46
+ - Particularly useful when checking batches of file edits or multiple similar commands.
47
+
48
+ ### How to use it
49
+
50
+ - Create your `LeanREPLConfig` with default settings (or ensure `enable_incremental_optimization=True`).
51
+ - Simply send commands to the same `LeanServer` instance as usual, incremental elaboration will be automatically applied.
52
+ - **Recommendation:** Instead of splitting your code into small chunks like in a REPL, you should send full commands or file contents. LeanInteract will find the best reuse points automatically.
53
+
54
+ ### Example
55
+
56
+ Below is a small script that measures the elapsed time of two "heavy" commands, but the second command benefits from incremental reuse:
57
+
58
+ ```python exec="on" source="above" session="perf" result="python"
59
+ import time
60
+ from lean_interact import LeanREPLConfig, LeanServer, Command
61
+
62
+ server = LeanServer(LeanREPLConfig())
63
+
64
+ t1 = time.perf_counter()
65
+ print(server.run(Command(cmd="""
66
+ def fib : Nat → Nat
67
+ | 0 => 0
68
+ | 1 => 1
69
+ | n + 2 => fib (n + 1) + fib n
70
+ #eval fib 35
71
+
72
+ theorem foo : n = n := by rfl
73
+ #check foo
74
+ """)))
75
+ print(f"First run: {time.perf_counter() - t1:.3f}s")
76
+
77
+ t2 = time.perf_counter()
78
+ print(server.run(Command(cmd="""
79
+ def fib : Nat → Nat
80
+ | 0 => 0
81
+ | 1 => 1
82
+ | n + 2 => fib (n + 1) + fib n
83
+ #eval fib 35
84
+
85
+ theorem foo2 : n = n+0 := by rfl
86
+ #check foo2
87
+ """)))
88
+ print(f"Second run: {time.perf_counter() - t2:.3f}s")
89
+ ```
90
+
91
+ !!! warning Imports are cached
92
+ Imports are cached in incremental mode, meaning that if the content of one of your imported file has changed, it will not be taken into account unless you restart the server.
93
+
94
+ You can disable this feature by setting `enable_incremental_optimization=False` in `LeanREPLConfig`.
95
+
96
+ ## Parallel Elaboration
97
+
98
+ When supported (Lean >= v4.19.0), Lean can elaborate different parts of a command/file in parallel. LeanInteract auto-enables this by adding `set_option Elab.async true` to each request.
99
+ You can disable it if needed by setting `enable_parallel_elaboration=False` in `LeanREPLConfig`.
100
+
101
+ !!! note
102
+ Only available for Lean >= v4.19.0
103
+
104
+ ---
105
+
106
+ ## Parallelization Guide (multiple commands)
107
+
108
+ LeanInteract is designed with parallelization in mind, allowing you to leverage multiple CPU cores for parallel theorem proving and verification tasks.
109
+
110
+ This section focuses on **external parallelization**: running multiple Lean servers (usually via `AutoLeanServer`) in parallel threads, processes or workers. This is complementary to the within-command optimizations above and can be combined with them.
111
+
112
+ We recommend using `AutoLeanServer`. It is specifically designed for parallel environments with automated restart on fatal Lean errors, timeouts, and when memory limits are reached. On automated restarts, only commands run with `add_to_session_cache=True` (attribute of the `AutoLeanServer.run` method) will be preserved.
113
+
114
+ `AutoLeanServer` is still experimental, feedback and issues are welcome.
115
+
116
+ ### Best Practices Summary
117
+
118
+ 1. **Always pre-instantiate** `LeanREPLConfig` before parallelization
119
+ 2. **One lean server per process/thread**
120
+ 3. **Use `AutoLeanServer`**
121
+ 4. **Configure memory limits** to prevent system overload
122
+ 5. **Set appropriate timeouts** for long-running operations
123
+ 6. **Use session caching** to keep context between requests
124
+ 7. **Consider using `maxtasksperchild`** to limit memory accumulation
125
+
126
+ ### Quick Start
127
+
128
+ ```python
129
+ from multiprocessing import Pool
130
+ from lean_interact import AutoLeanServer, Command, LeanREPLConfig
131
+ from lean_interact.interface import LeanError
132
+
133
+ def worker(config: LeanREPLConfig, task_id: int):
134
+ """Worker function that runs in each process"""
135
+ server = AutoLeanServer(config)
136
+ result = server.run(Command(cmd=f"#eval {task_id} * {task_id}"))
137
+ return f"Task {task_id}: {result.messages[0].data if not isinstance(result, LeanError) else 'Error'}"
138
+
139
+ # Pre-instantiate config before parallelization (downloads/initializes resources)
140
+ config = LeanREPLConfig(verbose=True)
141
+ with Pool() as p:
142
+ print(p.starmap(worker, [(config, i) for i in range(5)]))
143
+ ```
144
+
145
+ For more examples, check the [examples directory](https://github.com/augustepoiroux/LeanInteract/tree/main/examples).
146
+
147
+ ### Core Principles
148
+
149
+ #### 1. Pre-instantiate Configuration
150
+
151
+ Always create your `LeanREPLConfig` instance **before** starting parallelization:
152
+
153
+ ```python
154
+ from lean_interact import LeanREPLConfig, AutoLeanServer
155
+ import multiprocessing as mp
156
+
157
+ # ✅ CORRECT: Config created in main process
158
+ config = LeanREPLConfig() # Pre-setup in main process
159
+
160
+ def worker(cfg):
161
+ server = AutoLeanServer(cfg) # Use pre-configured config
162
+ # ... your work here
163
+ pass
164
+
165
+ ctx = mp.get_context("spawn")
166
+ with ctx.Pool() as pool:
167
+ pool.map(worker, [config] * 4)
168
+
169
+ # ❌ INCORRECT: Config created in each process
170
+ def worker():
171
+ config = LeanREPLConfig()
172
+ server = AutoLeanServer(config)
173
+ # ... your work here
174
+ pass
175
+
176
+ ctx = mp.get_context("spawn")
177
+ with ctx.Pool() as pool:
178
+ pool.map(worker, range(4))
179
+ ```
180
+
181
+ #### 2. One Server Per Process/Thread
182
+
183
+ Each process or thread should have its own `LeanServer` or `AutoLeanServer` instance.
184
+
185
+ ```python
186
+ def worker(config, task_data):
187
+ # Each process gets its own server
188
+ server = AutoLeanServer(config)
189
+
190
+ for task in task_data:
191
+ result = server.run(task)
192
+ # Handle result
193
+
194
+ return results
195
+ ```
196
+
197
+ ### Thread Safety
198
+
199
+ Within a single process, `LeanServer` and `AutoLeanServer` are thread-safe thanks to internal locking. All concurrent requests are processed sequentially. Across processes, servers are not shareable: each process must create its own instance.
200
+
201
+ Similarly, `ReplaySessionCache` is thread-safe within a process, meaning multiple `AutoLeanServer` in different threads can safely share the same cache instance. However, across processes, each must have its own cache instance.
202
+
203
+ ### Memory Management
204
+
205
+ ```python
206
+ from lean_interact import AutoLeanServer, LeanREPLConfig
207
+
208
+ # Configure memory limits for multi-process safety
209
+ config = LeanREPLConfig(memory_hard_limit_mb=8192) # 8GB per server, works on Linux only
210
+
211
+ server = AutoLeanServer(
212
+ config,
213
+ max_total_memory=0.8, # Restart when system uses >80% memory
214
+ max_process_memory=0.8, # Restart when process uses >80% of memory limit
215
+ max_restart_attempts=5 # Allow up to 5 restart attempts per command
216
+ )
217
+ ```
218
+
219
+ #### Memory Configuration Options
220
+
221
+ - `max_total_memory`: System-wide memory threshold (0.0-1.0)
222
+ - `max_process_memory`: Per-process memory threshold (0.0-1.0)
223
+ - `memory_hard_limit_mb`: Hard memory limit in MB (Linux only)
224
+ - `max_restart_attempts`: Maximum consecutive restart attempts
@@ -12,14 +12,20 @@
12
12
 
13
13
  Citation:
14
14
  ```bibtex
15
- @misc{poiroux2024improvingautoformalizationusingtype,
16
- title={Improving Autoformalization using Type Checking},
17
- author={Auguste Poiroux and Gail Weiss and Viktor Kunčak and Antoine Bosselut},
18
- year={2024},
19
- eprint={2406.07222},
20
- archivePrefix={arXiv},
21
- primaryClass={cs.CL},
22
- url={https://arxiv.org/abs/2406.07222},
15
+ @inproceedings{poiroux-etal-2025-reliable,
16
+ title = "Reliable Evaluation and Benchmarks for Statement Autoformalization",
17
+ author = "Poiroux, Auguste and
18
+ Weiss, Gail and
19
+ Kun{\v{c}}ak, Viktor and
20
+ Bosselut, Antoine",
21
+ booktitle = "Proceedings of the 2025 Conference on Empirical Methods in Natural Language Processing",
22
+ month = nov,
23
+ year = "2025",
24
+ publisher = "Association for Computational Linguistics",
25
+ url = "https://aclanthology.org/2025.emnlp-main.907/",
26
+ doi = "10.18653/v1/2025.emnlp-main.907",
27
+ pages = "17958--17980",
28
+ ISBN = "979-8-89176-332-6",
23
29
  }
24
30
  ```
25
31
  """
@@ -250,6 +256,12 @@ def beq_plus(
250
256
  console.print(Syntax(proof_exact, "lean4"))
251
257
  continue
252
258
 
259
+ # If trivially provable by assumption, we skip
260
+ if check_proof_sub(server, formal_code, context_env, formal_2_start_line, "assumption", timeout_per_proof):
261
+ if verbose:
262
+ console.print("Skipping as provable by assumption")
263
+ continue
264
+
253
265
  # 2. try to apply the base theorem directly
254
266
  proof_apply = check_proof_sub(
255
267
  server,
@@ -340,6 +352,10 @@ open Set Real Ideal Polynomial
340
352
  open scoped BigOperators"""
341
353
 
342
354
  formalization_pairs = [
355
+ ( # negative example -- not semantically equivalent
356
+ "theorem prediction (a b : ℤ) (ha : a ∣ b) : a ∣ (b : ℤ) :=",
357
+ "theorem ground_truth (a b : ℤ) : (Zsqrtd.ofInt a : GaussianInt) ∣ Zsqrtd.ofInt b → a ∣ b :=",
358
+ ),
343
359
  (
344
360
  "theorem random_name_1 {G : Type*} [Group G] [Fintype G] (h : Fintype.card G % 2 = 0) :\n ∃ a : G, a ≠ 1 ∧ a = a⁻¹ :=",
345
361
  "theorem random_name_2 {G : Type*} [Group G] [Fintype G] (hG2 : Even (card G)) :\n ∃ (a : G), a ≠ 1 ∧ a = a⁻¹ :=",
@@ -0,0 +1,125 @@
1
+ # /// script
2
+ # requires-python = ">=3.10"
3
+ # dependencies = ["lean-interact", "joblib"]
4
+ # ///
5
+ """
6
+ Example demonstrating multi-processing and multi-threading with LeanInteract.
7
+
8
+ This example shows the correct pattern for using LeanInteract with multiple processes:
9
+ 1. Pre-instantiate the config before starting multiprocessing
10
+ 2. Use spawn context for cross-platform compatibility
11
+ 3. Each process gets its own server instance
12
+
13
+ Run this example with: python examples/parallelization.py
14
+ """
15
+
16
+ import concurrent.futures
17
+ import multiprocessing as mp
18
+ import time
19
+ from contextlib import contextmanager
20
+
21
+ from joblib import Parallel, delayed # type: ignore
22
+
23
+ from lean_interact import AutoLeanServer, LeanREPLConfig
24
+ from lean_interact.interface import Command, LeanError
25
+
26
+
27
+ def worker(config: LeanREPLConfig, task_id: int) -> str:
28
+ """Worker function that runs in each process"""
29
+ try:
30
+ # Each process gets its own server instance
31
+ server = AutoLeanServer(config)
32
+ result = server.run(
33
+ Command(
34
+ cmd="""
35
+ def fib : Nat → Nat
36
+ | 0 => 0
37
+ | 1 => 1
38
+ | n + 2 => fib (n + 1) + fib n
39
+ #eval fib 32
40
+ """
41
+ )
42
+ )
43
+ if isinstance(result, LeanError):
44
+ return f"Task {task_id}: LeanError - {result}"
45
+ return f"Task {task_id}: {result.messages[0].data}"
46
+ except Exception as e:
47
+ return f"Task {task_id}: Exception - {e}"
48
+
49
+
50
+ def setup() -> tuple[LeanREPLConfig, list[int]]:
51
+ print("Setting up LeanREPLConfig (may take a few minutes the first time)...")
52
+ config = LeanREPLConfig(verbose=True)
53
+ print("Config setup complete.")
54
+
55
+ # Dummy tasks
56
+ tasks = list(range(8))
57
+
58
+ return config, tasks
59
+
60
+
61
+ @contextmanager
62
+ def timed_section(title: str, *, summary_prefix: str | None = None):
63
+ print("\n\n" + "=" * 40)
64
+ print(title)
65
+ start_time = time.time()
66
+ try:
67
+ yield
68
+ finally:
69
+ elapsed = time.time() - start_time
70
+ label = summary_prefix or title
71
+ print(f"{label} took {elapsed:.2f} seconds.")
72
+
73
+
74
+ def print_results(results: list[str]) -> None:
75
+ """Utility function to print results"""
76
+ print("\nResults:")
77
+ print("-" * 40)
78
+ for result in results:
79
+ print(result)
80
+
81
+
82
+ def sequential_baseline(config: LeanREPLConfig, tasks: list[int]) -> None:
83
+ """Run tasks sequentially for baseline comparison"""
84
+ with timed_section("Sequential Baseline", summary_prefix="Sequential processing"):
85
+ results = []
86
+ for task_id in tasks:
87
+ result = worker(config, task_id)
88
+ results.append(result)
89
+ print_results(results)
90
+
91
+
92
+ def multiprocessing_example(config: LeanREPLConfig, tasks: list[int]) -> None:
93
+ """Demonstrate multiprocessing with LeanInteract"""
94
+ with timed_section("Multi-processing Example", summary_prefix="Multi-processing"):
95
+ ctx = mp.get_context("spawn")
96
+ with ctx.Pool(processes=min(4, len(tasks))) as pool:
97
+ results = pool.starmap(worker, [(config, task_id) for task_id in tasks])
98
+ print_results(results)
99
+
100
+
101
+ def multithreading_example(config: LeanREPLConfig, tasks: list[int]) -> None:
102
+ """Demonstrate multithreading with LeanInteract"""
103
+ with timed_section("Multi-threading Example", summary_prefix="Multi-threading"):
104
+ results = []
105
+ with concurrent.futures.ThreadPoolExecutor(max_workers=min(4, len(tasks))) as executor:
106
+ future_to_task = {executor.submit(worker, config, task_id): task_id for task_id in tasks}
107
+ for future in concurrent.futures.as_completed(future_to_task):
108
+ results.append(future.result())
109
+ print_results(results)
110
+
111
+
112
+ def joblib_parallel_example(config: LeanREPLConfig, tasks: list[int]) -> None:
113
+ """Demonstrate joblib-based parallel execution with LeanInteract"""
114
+ with timed_section("Joblib Parallel Example", summary_prefix="Joblib parallel processing"):
115
+ results = Parallel(n_jobs=min(4, len(tasks)))(delayed(worker)(config, task_id) for task_id in tasks)
116
+ print_results(results)
117
+
118
+
119
+ if __name__ == "__main__":
120
+ config, tasks = setup()
121
+
122
+ multiprocessing_example(config, tasks)
123
+ joblib_parallel_example(config, tasks)
124
+ multithreading_example(config, tasks)
125
+ sequential_baseline(config, tasks)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lean-interact"
3
- version = "0.9.2"
3
+ version = "0.10.0"
4
4
  description = "LeanInteract is a Python package that allows you to interact with the Lean theorem prover."
5
5
  keywords = ["Lean", "theorem proving", "autoformalization", "REPL"]
6
6
  license = { file = "LICENSE" }
@@ -16,11 +16,14 @@ from lean_interact.project import (
16
16
  TempRequireProject,
17
17
  )
18
18
  from lean_interact.server import AutoLeanServer, LeanServer
19
+ from lean_interact.sessioncache import PickleSessionCache, ReplaySessionCache
19
20
 
20
21
  __all__ = [
21
22
  "LeanREPLConfig",
22
23
  "LeanServer",
23
24
  "AutoLeanServer",
25
+ "PickleSessionCache",
26
+ "ReplaySessionCache",
24
27
  "LeanRequire",
25
28
  "GitProject",
26
29
  "LocalProject",
@@ -33,7 +33,7 @@ from lean_interact.interface import (
33
33
  UnpickleEnvironment,
34
34
  UnpickleProofState,
35
35
  )
36
- from lean_interact.sessioncache import BaseSessionCache, PickleSessionCache
36
+ from lean_interact.sessioncache import BaseSessionCache, ReplaySessionCache
37
37
  from lean_interact.utils import _limit_memory, get_total_memory_usage, logger
38
38
 
39
39
  DEFAULT_TIMEOUT: int | None = None
@@ -287,7 +287,7 @@ class LeanServer:
287
287
  raise ConnectionAbortedError(
288
288
  f"The Lean server closed unexpectedly."
289
289
  f"\n{'-' * 50}\nstdout:\n{stdout}\n{'-' * 50}\nstderr:\n{stderr}\n{'-' * 50}"
290
- f"If stdout and stderr are empty or obscure, here is a list of possible reasons (not exhaustive):\n"
290
+ f"\nIf stdout and stderr are empty or obscure, here is a list of possible reasons (not exhaustive):\n"
291
291
  "- Not enough memory and/or compute available\n"
292
292
  "- The cached Lean REPL is corrupted. In this case, clear the cache using the `clear-lean-cache` command.\n"
293
293
  "- An uncaught exception in the Lean REPL"
@@ -438,11 +438,11 @@ class AutoLeanServer(LeanServer):
438
438
  max_total_memory: The maximum proportion of system-wide memory usage (across all processes) before triggering a Lean server restart. This is a soft limit ranging from 0.0 to 1.0, with default 0.8 (80%). When system memory exceeds this threshold, the server restarts to free memory. Particularly useful in multiprocessing environments to prevent simultaneous crashes.
439
439
  max_process_memory: The maximum proportion of the memory hard limit (set in `LeanREPLConfig.memory_hard_limit_mb`) that the Lean server process can use before restarting. This soft limit ranges from 0.0 to 1.0, with default 0.8 (80%). Only applied if a hard limit is configured in `LeanREPLConfig`.
440
440
  max_restart_attempts: The maximum number of consecutive restart attempts allowed before raising a `MemoryError` exception. Default is 5. The server uses exponential backoff between restart attempts.
441
- session_cache: The session cache to use, if specified.
441
+ session_cache: Optional session cache implementation. Defaults to `ReplaySessionCache()`.
442
+ Use `PickleSessionCache` if you explicitly need on-disk artifacts.
442
443
  """
443
- session_cache = (
444
- session_cache if session_cache is not None else PickleSessionCache(working_dir=config.working_dir)
445
- )
444
+ if session_cache is None:
445
+ session_cache = ReplaySessionCache()
446
446
  self._session_cache: BaseSessionCache = session_cache
447
447
  self._max_total_memory = max_total_memory
448
448
  self._max_process_memory = max_process_memory
@@ -453,7 +453,7 @@ class AutoLeanServer(LeanServer):
453
453
  if state_id is None:
454
454
  return None
455
455
  if state_id in self._session_cache:
456
- return self._session_cache[state_id].repl_id
456
+ return self._session_cache.get_repl_id(state_id, self)
457
457
  return state_id
458
458
 
459
459
  def restart(self, verbose: bool = False) -> None: