igriv commited on
Commit
e49a279
·
verified ·
1 Parent(s): d6c654e

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. README.md +3 -9
  2. app.py +275 -0
  3. requirements.txt +2 -0
README.md CHANGED
@@ -1,12 +1,6 @@
1
  ---
2
- title: Aristotle Prover
3
- emoji: 🐠
4
- colorFrom: purple
5
- colorTo: pink
6
- sdk: gradio
7
- sdk_version: 6.6.0
8
  app_file: app.py
9
- pinned: false
 
10
  ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Aristotle_Theorem_Prover
 
 
 
 
 
3
  app_file: app.py
4
+ sdk: gradio
5
+ sdk_version: 6.5.1
6
  ---
 
 
app.py ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Gradio UI for Aristotle theorem prover (informal mode).
4
+
5
+ Provides a simple interface for non-programmers to submit
6
+ mathematical problems and receive Lean 4 proofs.
7
+
8
+ Launch:
9
+ python aristotle_ui.py
10
+ """
11
+
12
+ import asyncio
13
+ import tempfile
14
+ import time
15
+ from pathlib import Path
16
+
17
+ import gradio as gr
18
+
19
+ from aristotlelib import api_request
20
+ from aristotlelib.project import Project, ProjectInputType, ProjectStatus
21
+
22
+ POLL_INTERVAL = 15 # seconds between status checks
23
+ MAX_POLL_TIME = 1800 # 30 minutes max wait
24
+
25
+
26
+ # ---------------------------------------------------------------------------
27
+ # Core logic
28
+ # ---------------------------------------------------------------------------
29
+
30
+ def _set_key(api_key: str) -> bool:
31
+ key = api_key.strip()
32
+ if not key:
33
+ return False
34
+ api_request.set_api_key(key)
35
+ return True
36
+
37
+
38
+ def _run_async(coro):
39
+ """Run an async coroutine from synchronous Gradio callback."""
40
+ loop = asyncio.new_event_loop()
41
+ try:
42
+ return loop.run_until_complete(coro)
43
+ finally:
44
+ loop.close()
45
+
46
+
47
+ def submit_problem(api_key: str, problem_text: str):
48
+ """Generator: submit a problem and poll until done."""
49
+ if not _set_key(api_key):
50
+ yield "Enter your Aristotle API key above.", "", ""
51
+ return
52
+ problem_text = problem_text.strip()
53
+ if not problem_text:
54
+ yield "Enter a problem or proof statement.", "", ""
55
+ return
56
+
57
+ logs = []
58
+
59
+ def log(msg):
60
+ logs.append(msg)
61
+ return "\n".join(logs)
62
+
63
+ # Submit
64
+ yield log("Submitting to Aristotle (informal mode)..."), "", ""
65
+
66
+ try:
67
+ project_id = _run_async(
68
+ Project.prove_from_file(
69
+ input_content=problem_text,
70
+ project_input_type=ProjectInputType.INFORMAL,
71
+ wait_for_completion=False,
72
+ auto_add_imports=False,
73
+ validate_lean_project=False,
74
+ )
75
+ )
76
+ except Exception as e:
77
+ yield log(f"Submission error: {e}"), "", ""
78
+ return
79
+
80
+ yield log(f"Submitted! Project ID: {project_id}"), "", project_id
81
+
82
+ # Poll for completion
83
+ elapsed = 0
84
+ while elapsed < MAX_POLL_TIME:
85
+ time.sleep(POLL_INTERVAL)
86
+ elapsed += POLL_INTERVAL
87
+
88
+ try:
89
+ project = _run_async(Project.from_id(project_id))
90
+ except Exception as e:
91
+ yield log(f"[{elapsed}s] Poll error: {e} (will retry)"), "", project_id
92
+ continue
93
+
94
+ status = project.status
95
+ pct = project.percent_complete
96
+ pct_str = f" ({pct}%)" if pct is not None else ""
97
+ yield log(f"[{elapsed}s] {status.value}{pct_str}"), "", project_id
98
+
99
+ if status == ProjectStatus.COMPLETE:
100
+ try:
101
+ with tempfile.TemporaryDirectory() as td:
102
+ out = Path(td) / "solution.lean"
103
+ _run_async(project.get_solution(output_path=out))
104
+ solution = out.read_text()
105
+ yield log("Proof retrieved!"), solution, project_id
106
+ except Exception as e:
107
+ yield log(f"Error downloading solution: {e}"), "", project_id
108
+ return
109
+
110
+ if status == ProjectStatus.FAILED:
111
+ yield log("Project FAILED. Aristotle could not find a proof."), "", project_id
112
+ return
113
+
114
+ yield log(f"Timed out after {MAX_POLL_TIME // 60} minutes. Use 'Check Project' with the ID above to check later."), "", project_id
115
+
116
+
117
+ def check_project(api_key: str, project_id: str):
118
+ """Check status of a previously submitted project."""
119
+ if not _set_key(api_key):
120
+ return "Enter your API key.", ""
121
+ project_id = project_id.strip()
122
+ if not project_id:
123
+ return "Enter a project ID.", ""
124
+
125
+ try:
126
+ project = _run_async(Project.from_id(project_id))
127
+ except Exception as e:
128
+ return f"Error: {e}", ""
129
+
130
+ info = f"Project: {project_id}\nStatus: {project.status.value}"
131
+ if project.percent_complete is not None:
132
+ info += f"\nProgress: {project.percent_complete}%"
133
+ if project.file_name:
134
+ info += f"\nFile: {project.file_name}"
135
+
136
+ solution = ""
137
+ if project.status == ProjectStatus.COMPLETE:
138
+ try:
139
+ with tempfile.TemporaryDirectory() as td:
140
+ out = Path(td) / "solution.lean"
141
+ _run_async(project.get_solution(output_path=out))
142
+ solution = out.read_text()
143
+ info += "\n\nSolution downloaded successfully."
144
+ except Exception as e:
145
+ info += f"\n\nError downloading solution: {e}"
146
+
147
+ return info, solution
148
+
149
+
150
+ def list_recent(api_key: str):
151
+ """List recent projects for this API key."""
152
+ if not _set_key(api_key):
153
+ return "Enter your API key."
154
+
155
+ try:
156
+ projects, _ = _run_async(Project.list_projects(limit=15))
157
+ except Exception as e:
158
+ return f"Error: {e}"
159
+
160
+ if not projects:
161
+ return "No projects found."
162
+
163
+ lines = []
164
+ for p in projects:
165
+ pct = f" ({p.percent_complete}%)" if p.percent_complete is not None else ""
166
+ desc = f" — {p.description[:60]}" if p.description else ""
167
+ lines.append(f"{p.project_id[:12]}... {p.status.value:14s}{pct}{desc}")
168
+ return "\n".join(lines)
169
+
170
+
171
+ # ---------------------------------------------------------------------------
172
+ # Build UI
173
+ # ---------------------------------------------------------------------------
174
+
175
+ EXAMPLES = [
176
+ ["Prove that the square root of 2 is irrational."],
177
+ ["Prove that for all natural numbers n, the sum 1 + 2 + ... + n equals n*(n+1)/2."],
178
+ ["Show that every continuous function on a closed bounded interval [a,b] is uniformly continuous."],
179
+ ["Prove that if p is prime and p divides a*b, then p divides a or p divides b."],
180
+ ]
181
+
182
+
183
+ def build_app() -> gr.Blocks:
184
+ with gr.Blocks(title="Aristotle Prover", theme=gr.themes.Soft()) as app:
185
+ gr.Markdown(
186
+ "# Aristotle Theorem Prover\n"
187
+ "Submit a mathematical problem or proof in plain English. "
188
+ "[Aristotle](https://harmonic.fun/) will formalize it in Lean 4 and attempt a proof.\n\n"
189
+ "You need an Aristotle API key — get one at [harmonic.fun](https://harmonic.fun/)."
190
+ )
191
+
192
+ api_key = gr.Textbox(
193
+ label="Aristotle API Key",
194
+ type="password",
195
+ placeholder="sk-...",
196
+ )
197
+
198
+ with gr.Tab("Prove"):
199
+ problem_input = gr.Textbox(
200
+ label="Problem statement",
201
+ lines=10,
202
+ placeholder=(
203
+ "State a theorem, lemma, or problem in plain English or LaTeX.\n\n"
204
+ "Examples:\n"
205
+ "- Prove that sqrt(2) is irrational.\n"
206
+ "- Show that every bounded monotone sequence converges.\n"
207
+ "- Prove: if G is a finite group of order p^n (p prime), then G has a nontrivial center."
208
+ ),
209
+ )
210
+
211
+ gr.Examples(
212
+ examples=EXAMPLES,
213
+ inputs=[problem_input],
214
+ label="Example problems",
215
+ )
216
+
217
+ submit_btn = gr.Button("Submit to Aristotle", variant="primary")
218
+
219
+ with gr.Row():
220
+ with gr.Column():
221
+ progress_log = gr.Textbox(
222
+ label="Progress",
223
+ lines=12,
224
+ interactive=False,
225
+ )
226
+ with gr.Column():
227
+ result_output = gr.Code(
228
+ label="Lean 4 Proof",
229
+ language=None,
230
+ lines=20,
231
+ )
232
+
233
+ project_id_state = gr.Textbox(visible=False)
234
+
235
+ submit_btn.click(
236
+ fn=submit_problem,
237
+ inputs=[api_key, problem_input],
238
+ outputs=[progress_log, result_output, project_id_state],
239
+ )
240
+
241
+ with gr.Tab("Check Project"):
242
+ gr.Markdown(
243
+ "Check on a previously submitted project by its ID, "
244
+ "or list your recent projects."
245
+ )
246
+
247
+ with gr.Row():
248
+ check_id = gr.Textbox(
249
+ label="Project ID",
250
+ placeholder="paste project ID here",
251
+ scale=3,
252
+ )
253
+ check_btn = gr.Button("Check", variant="primary", scale=1)
254
+ list_btn = gr.Button("List Recent", scale=1)
255
+
256
+ check_status = gr.Textbox(label="Status", lines=6, interactive=False)
257
+ check_solution = gr.Code(label="Lean 4 Proof", language=None, lines=20)
258
+
259
+ check_btn.click(
260
+ fn=check_project,
261
+ inputs=[api_key, check_id],
262
+ outputs=[check_status, check_solution],
263
+ )
264
+ list_btn.click(
265
+ fn=list_recent,
266
+ inputs=[api_key],
267
+ outputs=[check_status],
268
+ )
269
+
270
+ return app
271
+
272
+
273
+ if __name__ == "__main__":
274
+ app = build_app()
275
+ app.launch()
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ aristotlelib
2
+ gradio