Record and gate proofs, so "proven" means Lean verified it
The index had no proof field and every entry was an axiom, so the database asserted its premises rather than proving them. Adds the proof half, with the verification gate that makes the status trustworthy. - Database records now carry `proof` and `proof_checked`, and the search index exposes the proof, with status one of proved / proof_pending / asserted. build_database.py emits a real `theorem` only when a proof has been verified (by check_proofs.py, or by a lean-bench run via --results); a recorded but unverified proof stays an `axiom` and is reported as proof_pending, so the library never claims more than Lean has confirmed. A test pins that gating in both directions. - textbook/check_proofs.py verifies proofs by compiling `theorem ... := by <proof>`. Stricter than check_statements.py in three ways: it rejects sorry/admit/native_decide outright, and it reads `#print axioms` to reject any proof depending on more than Lean's own three axioms (propext, Classical.choice, Quot.sound) -- which in particular catches a proof leaning on one of this database's own book-asserted axioms, since that is not an independent proof. With --update it writes proof_checked back, promoting entries on the next build. - Ten candidate proofs recorded, all currently proof_checked=false pending a Lean run: goodman-1-6-1 (the eight algebraic identities are `ring`, plus a short argument for the nonzero conjunct), the four parts of Proposition 1.6.2 (Int.mul_eq_one_iff_eq_one_or_neg_one, associated_of_dvd_dvd with Int.associated_iff, dvd_trans, dvd_add with mul_left), 1-6-4 (Nat.exists_prime_and_dvd), 1-6-15 (Int.gcd_eq_one_iff_coprime, where IsCoprime unfolds to exactly the target existential), 1-6-17 (IsCoprime.mul_dvd via Nat.isCoprime_iff_coprime), 1-6-19 (Int.Prime.dvd_mul') and 1-6-20 (Prime.dvd_prod_iff). These are citations of existing Mathlib results, which is the realistic way to populate a textbook premise library -- the remaining 11 (1-6-6, -7, -9, -10, -11, -13, -18, -21, -23, -24, -26) are the ones needing actual work and carry no proof yet. Written without Lean available here, so expect a real failure rate on first compile -- run check_proofs.py --update and send back the FAILED ids with diagnostics, same loop as the statement fixes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017vbLFFJiHSZqGZHEkjvG5x
This commit is contained in:
@@ -98,20 +98,33 @@ def build(entries, results=None, require_checked=False):
|
||||
|
||||
name = decl_name(entry_id)
|
||||
result = results.get(entry_id)
|
||||
proved = bool(result and result.get('success') and result.get('attempts'))
|
||||
# A proof can come from a lean-bench run, or be recorded on the entry itself
|
||||
# (hand-written, or authored by an agent outside a bench run). Either way it
|
||||
# only counts once check_proofs.py has actually compiled it: an unverified
|
||||
# proof stays an axiom, so the library never claims more than Lean confirmed.
|
||||
run_proof = result['attempts'][-1]['proof'] if (
|
||||
result and result.get('success') and result.get('attempts')) else None
|
||||
own_proof = entry.get('proof') if entry.get('proof_checked') else None
|
||||
proof = run_proof or own_proof
|
||||
proved = bool(proof)
|
||||
proof_pending = bool(not proved and entry.get('proof'))
|
||||
provenance = entry.get('source_label', entry_id)
|
||||
|
||||
doc = f'/-- {provenance} (Goodman, Algebra: Abstract and Concrete).'
|
||||
if entry.get('natural_language'):
|
||||
doc += f' {entry["natural_language"].split("[fix note:")[0].strip()}'
|
||||
doc += (' Proven by lean-bench.' if proved
|
||||
else ' ASSERTED from the textbook, not proven here.') + ' -/'
|
||||
if proved:
|
||||
doc += ' Proof verified by Lean.'
|
||||
elif proof_pending:
|
||||
doc += ' ASSERTED from the textbook; a proof is recorded but not yet verified.'
|
||||
else:
|
||||
doc += ' ASSERTED from the textbook, not proven here.'
|
||||
doc += ' -/'
|
||||
lines.append(doc)
|
||||
|
||||
if proved:
|
||||
proof = result['attempts'][-1]['proof']
|
||||
lines.append(f'theorem {name} : {entry["statement"]} := by')
|
||||
lines.extend(' ' + line for line in proof.splitlines())
|
||||
lines.extend(' ' + line for line in proof.strip().splitlines())
|
||||
else:
|
||||
lines.append(f'axiom {name} : {entry["statement"]}')
|
||||
lines.append('')
|
||||
@@ -121,7 +134,8 @@ def build(entries, results=None, require_checked=False):
|
||||
"id": entry_id,
|
||||
"source_label": entry.get('source_label'),
|
||||
"kind": entry.get('kind'),
|
||||
"status": "proved" if proved else "asserted",
|
||||
"status": "proved" if proved else ("proof_pending" if proof_pending else "asserted"),
|
||||
"proof": proof if proved else entry.get('proof'),
|
||||
"statement": entry['statement'],
|
||||
"natural_language": entry.get('natural_language', '').split('[fix note:')[0].strip(),
|
||||
"identifiers": statement_identifiers(entry['statement']),
|
||||
@@ -154,7 +168,9 @@ def main():
|
||||
stream.write(json.dumps(record, ensure_ascii=False) + '\n')
|
||||
|
||||
proved = sum(1 for r in index if r['status'] == 'proved')
|
||||
print(f'{len(emitted)} premises -> {args.out_lean} ({proved} proven, {len(emitted) - proved} asserted as axioms)')
|
||||
pending = sum(1 for r in index if r['status'] == 'proof_pending')
|
||||
print(f'{len(emitted)} premises -> {args.out_lean} ({proved} proven, '
|
||||
f'{len(emitted) - proved} asserted as axioms, of which {pending} have an unverified proof)')
|
||||
print(f'search index -> {args.out_index}')
|
||||
if skipped:
|
||||
print(f'{len(skipped)} skipped for not being elaboration-checked: {", ".join(skipped)}')
|
||||
|
||||
Reference in New Issue
Block a user