04d827b3b3
Restructures the textbook pipeline around the distinction the body-derived dataset had been blurring: a bench should be actual unsolved problems, and a reusable premise library should only ever contain statements that have really been proven, the way Mathlib itself works. - library_candidates/goodman-1.6.jsonl (renamed from datasets/goodman-1.6.jsonl): the book's own Theorem/Proposition/Lemma/Corollary claims from the main text. Not bench targets -- premises waiting to be proven once via a real lean-bench run, then assembled into the reusable library by build_library.py (which already only keeps success:true entries with their checked proof, unchanged by this commit). - datasets/goodman-1.6-exercises.jsonl (new): the actual bench, sourced from the book's Exercises 1.6 block via two new scripts, textbook/extract_exercises.py (slices the Exercises block, lists its numbered items, drops a known false-positive class where a wrapped cross-reference like "...Proposition\n1.6.19." looks like a real exercise heading) and textbook/formalize_exercises.py (LLM step, given both the exercises and body text together since many exercises say "Prove Proposition N.N.N" instead of restating the claim). - Both formalize.py and formalize_exercises.py's validate() now enforce that every checklist item is covered by at least one output entry (included or explicitly excluded with a reason); formalize_exercises.py did not have this yet and a first real run silently dropped 7 of 15 checklist items with no trace before this was added. - All 12 model-produced exercise entries needed real fixes before commit, the same review pass applied to the body pilot: 3 exercises literally ask to prove an already-stated body claim (Exercise 1.6.1 -> Proposition 1.6.7, 1.6.2 -> Proposition 1.6.9, 1.6.7 -> Proposition 1.6.18, 1.6.9 -> Corollary 1.6.20, 1.6.15 -> Lemma 1.6.26) and now reuse that claim's own already-checked statement verbatim instead of an independently re-derived (and in one case strictly weaker) restatement; two entries (1.6.2, 1.6.11) had literal math prose like "I(m, n)" or "gcd(n1,...,nk)" leaked into the statement field, which is not valid Lean; several had untyped/ambiguous gcd or Prime usage fixed the same way the earlier body fixes were (Nat.Prime, IsCoprime, explicit casts, IsGreatest instead of max on a Set); and Exercise 1.6.12 part (a) turned out to be a discussion question whose unconditional-identity reading is actually false (6, 10, 15 are jointly coprime but not pairwise coprime), so it was moved to the excluded file with a reason instead of committed as a false theorem. - Definitions can now be real, compiled Lean, not only JSON metadata: Definition 1.6.22 (gcd of a list of integers, previously a null placeholder since no single Mathlib constant matches it) now has a real hand-written `def IsGCDOfList`, and textbook/build_definitions.py compiles any manifest's non-null lean_code entries into lib/Definitions.lean. goodman-1-6-24 (library) and the new goodman-1-6-ex-11-b/c, goodman-1-6-ex-12 (bench) all now use IsGCDOfList instead of repeating an inline existential. - textbook/README.md rewritten around the two-track design and records how this is meant to connect to lean-agent's eventual goal-directed proof search against the growing library (not yet built). - New tests for extract_exercises.py and build_definitions.py; full local suite still green (18/19, the one failure is the pre-existing, unrelated lean_agent import error in test_dataset.py). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017vbLFFJiHSZqGZHEkjvG5x
56 lines
2.2 KiB
Python
56 lines
2.2 KiB
Python
"""Assemble a standalone, importable Lean 4 file from a definitions manifest's
|
|
hand-written lean_code entries.
|
|
|
|
Only definitions with no Mathlib equivalent need one -- when a manifest entry's
|
|
mathlib_ref is set, the theorems that use it just reference that Mathlib name
|
|
directly, and there is nothing to assemble here. This exists because a definitions
|
|
manifest is only JSON metadata by itself: Lean can't verify a proof that mentions a
|
|
concept unless that concept is actual Lean code somewhere it can see, which is the
|
|
point raised about definitions needing to be real, not just documented.
|
|
|
|
Does not call Lean itself -- check_statements.py / lean-agent still has to actually
|
|
verify that the resulting file, and anything that imports it, type-checks.
|
|
"""
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
|
|
|
|
def build(definitions_paths):
|
|
entries = []
|
|
for path in definitions_paths:
|
|
entries.extend(json.loads(path.read_text(encoding='utf-8')))
|
|
|
|
lines = ['-- Generated by textbook/build_definitions.py -- hand-written Lean',
|
|
'-- definitions for concepts with no Mathlib equivalent. Regenerate',
|
|
'-- from the definitions manifest(s) instead of hand-editing.',
|
|
'', 'import Mathlib', '']
|
|
emitted = 0
|
|
for entry in entries:
|
|
code = entry.get('lean_code')
|
|
if not code:
|
|
continue
|
|
lines.append(f"-- {entry['label']}: {entry['concept']}")
|
|
if entry.get('notes'):
|
|
for note_line in entry['notes'].splitlines():
|
|
lines.append(f"-- {note_line}")
|
|
lines.append(code.rstrip())
|
|
lines.append('')
|
|
emitted += 1
|
|
return '\n'.join(lines), emitted
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description='Assemble hand-written definitions into one importable Lean file')
|
|
parser.add_argument('definitions', type=Path, nargs='+', help='one or more *.definitions.json manifests')
|
|
parser.add_argument('--out', type=Path, required=True)
|
|
args = parser.parse_args()
|
|
|
|
text, emitted = build(args.definitions)
|
|
args.out.write_text(text + '\n', encoding='utf-8')
|
|
print(f'{emitted} hand-written definitions -> {args.out}')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|