For each line Dafny fails on in the integ5 translations, the Lean step it translates and the part of that step's proof left to Z3. Click a line in the browser below to see the failing Dafny line, the Lean step with Lean's recorded goal, the extracted subgoal lemma (original and trimmed) and the reviewers' consensus.
Round integ5 (2026-10-02/03) is the candidate translator that states every Lean tactic's recorded before-goal as a Dafny statement (// @tac), Lean's rewritten hypotheses (// @tac-hyp), and only the lemma applications Lean recorded at each step, with Lean's arguments. All 101 theorems were verified once with the same bar as before (dafny verify --isolate-assertions --resource-limit 1000000 --allow-warnings --cores 2, Dafny 4.11). Each failing line was extracted from the integ5 output files as one subgoal lemma (encode-only, then trimmed statically by simple_trim v3), each lemma checked standalone once as extracted and once trimmed, and labelled independently by three reviewers (A, B, C) with the T/S/R gap taxonomy plus a fix task (who has to act). Where they disagreed on the primary label or the fix task, an adjudicator re-read the evidence (≤ 3 standalone Dafny checks per line) and decided; the decision and its reason are shown on the line.
| label | error | OOR | total | any role | |
|---|---|---|---|---|---|
| T-FAITHFUL | 2 | 1 | 3 | 8 | |
| T-SORT | 3 | 1 | 4 | 22 | |
| T-BACKWARD | 2 | · | 2 | 3 | |
| T-CITE | 32 | 42 | 74 | 98 | |
| T-LIBRARY | 16 | 29 | 45 | 69 | |
| S-RELEVANCE | 18 | 140 | 158 | 245 | |
| S-INSTANTIATE | 37 | 4 | 41 | 56 | |
| S-COMPUTE | 17 | 94 | 111 | 281 | |
| R-NONLINEAR | 37 | 11 | 48 | 147 | |
| R-FIELD | 11 | · | 11 | 34 | |
| R-TRANSCENDENTAL | · | · | · | 31 | |
| R-BINDER | · | 1 | 1 | 22 | |
| R-INDUCTION | · | · | · | 2 | |
| R-CASES | · | 1 | 1 | 6 | |
| total | 175 | 324 | 499 |
pow encoding, not Z3, is the cause (lines that moved).| fix task | error | OOR | total |
|---|---|---|---|
| TRANSLATOR the emitter must change (a named change) | 112 | 108 | 220 |
| LIBRARY a Mathlib fact must be added to / restated in the Dafny library | 29 | 88 | 117 |
| HARVEST Lean's records are missing or misattributed, so the fact could not be stated | 7 | 4 | 11 |
| SOLVER true, faithfully stated, facts present — Z3 cannot do it (no translator fix) | 27 | 124 | 151 |
| AUDIT-KNOWN matches a confirmed audit5 finding | · | · | · |
| primary | TRANS | LIBRA | HARVE | SOLVE | AUDIT | total |
|---|---|---|---|---|---|---|
| T-FAITHFUL | 2 | · | 1 | · | · | 3 |
| T-SORT | 4 | · | · | · | · | 4 |
| T-BACKWARD | 2 | · | · | · | · | 2 |
| T-CITE | 63 | 4 | 7 | · | · | 74 |
| T-LIBRARY | · | 45 | · | · | · | 45 |
| S-RELEVANCE | 36 | 6 | · | 116 | · | 158 |
| S-INSTANTIATE | 36 | 4 | 1 | · | · | 41 |
| S-COMPUTE | 39 | 54 | 1 | 17 | · | 111 |
| R-NONLINEAR | 32 | · | 1 | 15 | · | 48 |
| R-FIELD | 4 | 4 | · | 3 | · | 11 |
| R-BINDER | 1 | · | · | · | · | 1 |
| R-CASES | 1 | · | · | · | · | 1 |
| # | task | change | error | OOR | lines | theorems (lines) | |
|---|---|---|---|---|---|---|---|
| 1 | LIBRARY | LIBRARY: stop the MathPrelude pow matching loop (opaque pow with explicit PowSucc/PowAdd/PowMul lemmas instead of the recursive ensures) | 4 | 53 | 57 | numbertheory_fxeq4powxp6powxp9powx_f2powmdvdf2pown (17), imo_1966_p4 (9), amc12a_2009_p15 (8), imo_1964_p1_2 (7), algebra_apbon2pownleqapownpbpowon2 (5), numbertheory_3pow2pownm1mod2pownp3eq2pownp2 (5), imo_1964_p1_1 (4), amc12a_2021_p14 (1), mathd_numbertheory_175 (1) | show |
| 2 | TRANSLATOR | TRANSLATOR: in interval_cases/norm_num branches state the evaluated h0 instance p(k)==v and norm_num's isNat_gcd result gcd(x,y)==z | 7 | 25 | 32 | mathd_numbertheory_618 (32) | show |
| 3 | TRANSLATOR | TRANSLATOR: hoist inline guarded nlinarith certificate pieces (mul_zero_eq/zero_mul_eq/sq_nonneg) into context-free cert_piece lemmas | 4 | 25 | 29 | imo_1965_p1 (19), imo_1973_p3 (6), amc12a_2021_p22 (3), algebra_apbpceq2_abpbcpcaeq1_aleq1on3anbleq1ancleq4on3 (1) | show |
| 4 | TRANSLATOR | TRANSLATOR: emit quantified hypothesis bodies (∀, ∃, ∀-iff) through named ghost predicates/functions so they have matchable triggers | 22 | · | 22 | amc12a_2003_p25 (19), algebra_apbon2pownleqapownpbpowon2 (1), amc12a_2021_p19 (1), numbertheory_fxeq4powxp6powxp9powx_f2powmdvdf2pown (1) | show |
| 5 | LIBRARY | LIBRARY: add Mathlib Rat.cast_injective / Rat.cast_inj with Rat.cast_neg and Rat.cast_intCast (ℚ→ℝ) | 4 | 12 | 16 | aime_1984_p1 (12), aime_1999_p11 (2), amc12a_2009_p2 (2) | show |
| 6 | TRANSLATOR | TRANSLATOR: emit cert_piece bodies with let-bound factors, the MulPos call, and an explicit product-equality assert | 12 | · | 12 | imo_1974_p5 (8), amc12a_2021_p22 (2), imo_1966_p5 (2) | show |
| 7 | TRANSLATOR | TRANSLATOR: cite IntMulNonneg for ℕ products passed to nat parameters | · | 11 | 11 | numbertheory_3pow2pownm1mod2pownp3eq2pownp2 (10), amc12_2001_p5 (1) | show |
| 8 | TRANSLATOR | TRANSLATOR: generalise cert_piece factors (compound products, cast atoms, Real.pow atoms) to lemma parameters instantiated at the call site | 8 | 1 | 9 | algebra_abpbcpcageq3_sumaonsqrtapbgeq3onsqrt2 (3), aime_1999_p11 (2), algebra_apbon2pownleqapownpbpowon2 (2), amc12_2000_p20 (2) | show |
| 9 | TRANSLATOR | TRANSLATOR: instantiate named simp/norm_num hint lemmas with no recorded instance by matching their LHS against the before-goal | 7 | 2 | 9 | amc12b_2020_p21 (6), aime_1999_p11 (1), mathd_numbertheory_175 (1), mathd_numbertheory_84 (1) | show |
| 10 | TRANSLATOR | TRANSLATOR: emit argument-free trig special-value lemmas (RealSin/CosZero, RealSin/CosPiDivTwo) for ground terms in norm_num/simp goals | 4 | 4 | 8 | amc12a_2021_p19 (8) | show |
| 11 | LIBRARY | LIBRARY: add Mathlib Complex.re_sum / Complex.im_sum (with ℂ Finset.sum_singleton) | · | 7 | 7 | amc12a_2009_p15 (7) | show |
| 12 | TRANSLATOR | TRANSLATOR: emit Dvd-iff-mod cite with Lean's witness for ∃-form divisibility proofs (use w / exact ⟨w, _⟩ / Dvd.intro) | · | 7 | 7 | numbertheory_3pow2pownm1mod2pownp3eq2pownp2 (5), aime_1987_p5 (1), numbertheory_fxeq4powxp6powxp9powx_f2powmdvdf2pown (1) | show |
| 13 | TRANSLATOR | TRANSLATOR: map recorded Real.logb.eq_1 (and ground logb terms in simp/field_simp) to RealLogbUnfold | 4 | 2 | 6 | amc12a_2021_p14 (6) | show |
| 14 | TRANSLATOR | TRANSLATOR: ring-normalise cert_identity summands into monomials | · | 6 | 6 | imo_1992_p1 (6) | show |
| 15 | TRANSLATOR | TRANSLATOR: add {:trigger f(n)} to ∀ recurrence hypotheses (or emit the instance's parity/tsub side facts) | 5 | · | 5 | amc12a_2017_p7 (5) | show |
| 16 | LIBRARY | LIBRARY: add Mathlib Finset.sum_singleton for ℕ-indexed/generic sets (Real.sum) | 2 | 2 | 4 | aime_1999_p11 (1), algebra_sum1onsqrt2to1onsqrt10000lt198 (1), amc12a_2021_p14 (1), imo_1966_p4 (1) | show |
| 17 | TRANSLATOR | TRANSLATOR: bridge %-based Dvd hypotheses to ∃-form preconditions and back (IntDvdIffEmodEqZero / NatModAddDiv glue) | 1 | 3 | 4 | aime_1987_p5 (2), numbertheory_2pownm1prime_nprime (2) | show |
| 18 | TRANSLATOR | TRANSLATOR: emit ∀-have instances as calls of a hoisted lemma (or its proving induction helper) with Lean's arguments | 1 | 3 | 4 | numbertheory_fxeq4powxp6powxp9powx_f2powmdvdf2pown (2), aime_1999_p11 (1), algebra_absapbon1pabsapbleqsumabsaon1pabsa (1) | show |
| 19 | TRANSLATOR | TRANSLATOR: map recorded Set.InjOn.eq_iff (cos on Icc 0 π, tan on Ioo) to RealInjOnCosEqIff / RealInjOnTanEqIff | 2 | 2 | 4 | amc12a_2021_p19 (3), aime_1999_p11 (1) | show |
| 20 | LIBRARY | LIBRARY: add Mathlib Nat.pow_le_pow_right (Int.pow, nat exponent) | · | 3 | 3 | numbertheory_2pownm1prime_nprime (3) | show |
| 21 | LIBRARY | LIBRARY: make MathPrelude Real.sqrt ensures-free/opaque (facts via cited Real.sq_sqrt / Real.sqrt_nonneg) | 3 | · | 3 | aime_1983_p3 (3) | show |
| 22 | TRANSLATOR | TRANSLATOR: do not re-assert trigger-less ∀/∃ hypotheses at exact/obtain; assert the instance or bind the witness directly | 2 | 1 | 3 | numbertheory_fxeq4powxp6powxp9powx_f2powmdvdf2pown (2), numbertheory_3pow2pownm1mod2pownp3eq2pownp2 (1) | show |
| 23 | TRANSLATOR | TRANSLATOR: emit cert pieces with compound-product factors without the MulPos/MulNonneg call (empty body), and state order-lemma conclusions directly | 3 | · | 3 | algebra_bleqa_apbon2msqrtableqambsqon8b (2), mathd_algebra_362 (1) | show |
| 24 | TRANSLATOR | TRANSLATOR: emit rw / ring_nf congruence steps as explicit before==after (argument) equalities | 2 | 1 | 3 | algebra_bleqa_apbon2msqrtableqambsqon8b (1), imo_1960_p2 (1), numbertheory_aoddbdiv4asqpbsqmod8eq1 (1) | show |
| 25 | TRANSLATOR | TRANSLATOR: emit ℚ literal norm_num helpers (RatMulOfIntOfInt / RatMulDivOfIntCancel) for Rat literal products | 2 | 1 | 3 | amc12a_2021_p18 (3) | show |
| 26 | TRANSLATOR | TRANSLATOR: render squares uniformly (x*x vs Real.pow/Int.pow(x,2)) or emit the pow-two bridge after cites | 2 | 1 | 3 | algebra_bleqa_apbon2msqrtableqambsqon8b (1), amc12a_2021_p14 (1), amc12b_2020_p13 (1) | show |
| 27 | LIBRARY | LIBRARY: add Mathlib Nat.gcd_self_add_right (nat gcd) | · | 2 | 2 | imo_1959_p1 (1), mathd_numbertheory_618 (1) | show |
| 28 | LIBRARY | LIBRARY: add Mathlib Nat.prime_def_lt'' (PrimeOfNoDivisor) for decide on Nat.Prime literals | 2 | · | 2 | amc12a_2021_p18 (2) | show |
| 29 | LIBRARY | LIBRARY: add Mathlib add_div and div_self (Real.div) | 2 | · | 2 | amc12b_2020_p13 (2) | show |
| 30 | LIBRARY | LIBRARY: add Mathlib div_add_div / div_add' / add_div' (Real.div) | 2 | · | 2 | imo_1974_p5 (2) | show |
| 31 | LIBRARY | LIBRARY: add Mathlib div_eq_iff (real, Real.div form) | 2 | · | 2 | aime_1983_p1 (1), mathd_algebra_598 (1) | show |
| 32 | LIBRARY | LIBRARY: add pointwise (h-form) Finset.sum_add_distrib at ℚ (FinsetSumAddDistribRatH) | · | 2 | 2 | aime_1984_p1 (2) | show |
| 33 | LIBRARY | LIBRARY: add ℚ nsmul_eq_mul and h-form Finset.sum_const at ℚ | · | 2 | 2 | aime_1984_p1 (2) | show |
| 34 | TRANSLATOR | TRANSLATOR: compose ∣-calc chains with NatDvdTrans | · | 2 | 2 | numbertheory_3pow2pownm1mod2pownp3eq2pownp2 (2) | show |
| 35 | TRANSLATOR | TRANSLATOR: emit `tac at h ⊢` / ring_nf @tac-hyp haves as context-free helper lemmas requiring only the named hypotheses | · | 2 | 2 | imo_1984_p2 (1), imo_1992_p1 (1) | show |
| 36 | TRANSLATOR | TRANSLATOR: emit at-hypothesis rewrite instances at the @tac-hyp line and bind literal-exponent Real.pow terms to a name | 2 | · | 2 | amc12b_2003_p17 (2) | show |
| 37 | TRANSLATOR | TRANSLATOR: emit log-positivity unguarded and the `/`-form of field_simp goals over Real.div | 2 | · | 2 | amc12b_2021_p9 (2) | show |
| 38 | TRANSLATOR | TRANSLATOR: emit refine' lt_of_sub_pos sub-goal before the LtOfSubPosReal precondition | 2 | · | 2 | imo_1974_p5 (2) | show |
| 39 | TRANSLATOR | TRANSLATOR: hoist the whole nlinarith closing step (sub-goal + pieces + cert_identity) into a lemma requiring only its premises | 2 | · | 2 | algebra_apbpceq2_abpbcpcaeq1_aleq1on3anbleq1ancleq4on3 (1), imo_1973_p3 (1) | show |
| 40 | TRANSLATOR | TRANSLATOR: map Finset.mul_sum over ℕ-indexed sets to FinsetMulSumPointwise<T> | 1 | 1 | 2 | aime_1999_p11 (1), amc12a_2021_p14 (1) | show |
| 41 | TRANSLATOR | TRANSLATOR: map Int.card_Icc to IntIccCard (recorded instance or literal-bounded rfl/decide card goals) | 2 | · | 2 | amc12b_2021_p1 (1), mathd_algebra_170 (1) | show |
| 42 | TRANSLATOR | TRANSLATOR: prove rewritten ∀ @tac-hyp restatements with a forall-statement body (instance / FinsetMemIccNat guard lemma) | 2 | · | 2 | algebra_sum1onsqrt2to1onsqrt10000lt198 (1), amc12a_2009_p9 (1) | show |
| 43 | TRANSLATOR | TRANSLATOR: state field_simp rewrites (goal before==after, internal div_pow instances) as explicit equalities over the literal terms | 2 | · | 2 | algebra_9onxpypzleqsum2onxpy (1), algebra_abpbcpcageq3_sumaonsqrtapbgeq3onsqrt2 (1) | show |
| 44 | LIBRARY | LIBRARY: add Complex Finset.sum_Icc_succ_top over ℤ-Icc and a root-of-unity inverse lemma | 1 | · | 1 | amc12a_2019_p21 (1) | show |
| 45 | LIBRARY | LIBRARY: add Complex.sum ℤ-Icc ↔ ℕ-IccN reindexing lemma (Finset.sum_nbij along Nat.cast) | 1 | · | 1 | amc12a_2019_p21 (1) | show |
| 46 | LIBRARY | LIBRARY: add IntDvd-form (%-based) Mathlib dvd_add_right | · | 1 | 1 | aime_1987_p5 (1) | show |
| 47 | LIBRARY | LIBRARY: add Mathlib Finset.prod_div_distrib (Real.prod, h-form) | 1 | · | 1 | amc12a_2008_p4 (1) | show |
| 48 | LIBRARY | LIBRARY: add Mathlib Nat.card_Icc for IccN | · | 1 | 1 | amc12a_2021_p14 (1) | show |
| 49 | LIBRARY | LIBRARY: add Mathlib Nat.cast_prod (Int.prod cast to Real.prod) | 1 | · | 1 | amc12a_2008_p4 (1) | show |
| 50 | LIBRARY | LIBRARY: add Mathlib Nat.gcd_mul_right_add_right / Nat.gcd_add_self_right / Nat.gcd_one_left (nat gcd) | · | 1 | 1 | imo_1959_p1 (1) | show |
| 51 | LIBRARY | LIBRARY: add Mathlib div_eq_div_iff (real, Real.div form) | 1 | · | 1 | amc12a_2013_p4 (1) | show |
| 52 | LIBRARY | LIBRARY: add Mathlib div_sub_div_same (Real.div) | 1 | · | 1 | amc12b_2021_p9 (1) | show |
| 53 | LIBRARY | LIBRARY: add Mathlib mul_div_assoc' (Real.div form) | 1 | · | 1 | algebra_sum1onsqrt2to1onsqrt10000lt198 (1) | show |
| 54 | LIBRARY | LIBRARY: add Mathlib one_pow at ℂ (ComplexOnePow) | · | 1 | 1 | amc12a_2009_p15 (1) | show |
| 55 | LIBRARY | LIBRARY: add RealRpowMul variant with explicit exponent-product argument (Mathlib Real.rpow_mul) | 1 | · | 1 | amc12a_2009_p6 (1) | show |
| 56 | LIBRARY | LIBRARY: restate ExistsDvdOfNotPrime2 with NatDvd in its ensures | · | 1 | 1 | numbertheory_2pownm1prime_nprime (1) | show |
| 57 | TRANSLATOR | TRANSLATOR: assert the induction-helper postcondition at the end of each branch | · | 1 | 1 | amc12a_2009_p15 (1) | show |
| 58 | TRANSLATOR | TRANSLATOR: cite ComplexSumEmpty and state ground Complex.mul intermediates in the induction base case | · | 1 | 1 | amc12a_2009_p15 (1) | show |
| 59 | TRANSLATOR | TRANSLATOR: constant-fold Nat-literal casts into real literals (Nat.cast_ofNat) | 1 | · | 1 | amc12a_2009_p6 (1) | show |
| 60 | TRANSLATOR | TRANSLATOR: emit Finset.sum summand lambdas as named ghost functions | · | 1 | 1 | imo_1966_p4 (1) | show |
| 61 | TRANSLATOR | TRANSLATOR: emit NotIrrationalNatCast / Irrational-definition instance for anonymous-constructor proofs on Irrational | 1 | · | 1 | algebra_others_exirrpowirrrat (1) | show |
| 62 | TRANSLATOR | TRANSLATOR: emit Real.div == `/` bridge at `/`-form division-lemma cites (LeDivIff) | 1 | · | 1 | algebra_abpbcpcageq3_sumaonsqrtapbgeq3onsqrt2 (1) | show |
| 63 | TRANSLATOR | TRANSLATOR: emit Set.ext_iff steps as pointwise forall with explicit iset membership asserts | 1 | · | 1 | amc12a_2003_p25 (1) | show |
| 64 | TRANSLATOR | TRANSLATOR: emit an execution's recorded cites before its @tac-hyp asserts | 1 | · | 1 | algebra_sum1onsqrt2to1onsqrt10000lt198 (1) | show |
| 65 | TRANSLATOR | TRANSLATOR: emit cert_identity over unevaluated pow atoms instead of norm_num-evaluated huge numerals | 1 | · | 1 | amc12a_2013_p4 (1) | show |
| 66 | TRANSLATOR | TRANSLATOR: emit interval_cases as an if/else-if chain on n == k | · | 1 | 1 | mathd_numbertheory_618 (1) | show |
| 67 | TRANSLATOR | TRANSLATOR: map isNat_rpow_pos (real base, numeral exponent) to RealRpowNatCast | 1 | · | 1 | mathd_algebra_756 (1) | show |
| 68 | TRANSLATOR | TRANSLATOR: map recorded Finset.prod_pair to FinsetProdPair | 1 | · | 1 | aime_1983_p3 (1) | show |
| 69 | TRANSLATOR | TRANSLATOR: map recorded Finset.sum_singleton over range 1 to FinsetSumRangeSucc/FinsetSumRangeZero | 1 | · | 1 | mathd_algebra_342 (1) | show |
| 70 | TRANSLATOR | TRANSLATOR: map recorded Nat.mod_mod_of_dvd to NatModMod (with IntPowPos precondition) | · | 1 | 1 | numbertheory_3pow2pownm1mod2pownp3eq2pownp2 (1) | show |
| 71 | TRANSLATOR | TRANSLATOR: map recorded orderOf_eq_iff on ZMod n to OrderOfEqIff | · | 1 | 1 | imo_1964_p1_1 (1) | show |
| 72 | TRANSLATOR | TRANSLATOR: restate the cases-succ branch conclusion over the outer binder (IccN/pow argument bridges for the predecessor var) | · | 1 | 1 | imo_1966_p4 (1) | show |
| 73 | TRANSLATOR | TRANSLATOR: split capped interval_cases enumerations into per-value helper lemmas | · | 1 | 1 | imo_1984_p2 (1) | show |
| statement kind | error | OOR | total |
|---|---|---|---|
| sub-goal (Lean tactic state) | 43 | 117 | 160 |
| have / step assertion | 61 | 84 | 145 |
| hypothesis after tactic (@tac-hyp) | 17 | 37 | 54 |
| cert (lemma application in a certificate) | 8 | 29 | 37 |
| cert piece | 28 | 1 | 29 |
| instance of a hypothesis | 5 | 13 | 18 |
| cert identity | 3 | 12 | 15 |
| contract (ensures/requires) | · | 12 | 12 |
| precondition (asserted lemma precondition) | 3 | 7 | 10 |
| cite (library lemma call) | 1 | 8 | 9 |
| lemma call (precondition) | 2 | 2 | 4 |
| such-that (:|) existence | 2 | · | 2 |
| other | · | 2 | 2 |
| contradiction closing a branch | 1 | · | 1 |
| postcondition at return point | 1 | · | 1 |
For each failing Dafny line: how many Lean source lines it stands for that the translator did not turn into Dafny statements of their own — the part of the Lean proof Z3 has to rediscover. The line browser below marks these Lean lines with ».
Why the raw » count overstated large blocks. The » marks are made from the Lean tactic tags (// @tac) attached to the Dafny line, each with the byte range of its Lean source. Two things inflate a plain count of » lines: (1) one Dafny statement can carry the tags of several consecutive haves, and (2) a have tag's byte range spans the whole nested by proof of that have — but that nested proof is translated separately, as its own Dafny statements, so it is not missing at this line. Example: imo_1966_p4-86 carries ten tags, four of them multi-line haves (base_case, inductive_step, apply_induction, final_conclusion); the raw count is 70 » lines, the corrected count 10. Corrected count: a have/obtain/show with a nested proof counts as its statement line only; every other tactic counts its source lines (recount() in classify5/gapset.py).
| missing Lean lines | lines, raw » count | lines, corrected | error | OOR | closes standalone (as extracted) | closes trimmed | TRANSLATOR | LIBRARY | SOLVER | HARVEST |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 (no » mark) | 168 | 168 | 73 | 95 | 86 (51%) | 86 | 99 | 25 | 42 | 2 |
| 1 | 209 | 209 | 57 | 152 | 40 (19%) | 41 | 82 | 60 | 58 | 9 |
| 2 | 25 | 32 | 11 | 21 | 11 (34%) | 12 | 9 | 8 | 15 | 0 |
| 3-5 | 47 | 60 | 25 | 35 | 18 (30%) | 17 | 21 | 12 | 27 | 0 |
| 6-10 | 24 | 22 | 9 | 13 | 4 (18%) | 5 | 7 | 7 | 8 | 0 |
| 11+ | 26 | 8 | 0 | 8 | 1 (12%) | 1 | 2 | 5 | 1 | 0 |
| all | 499 | 499 | 175 | 324 | 160 (32%) | 162 | 220 | 117 | 151 | 11 |
pow encoding) and some to translator/harvest. Labels and named fixes are the three-reviewer consensus.| missing Lean lines | lines | error / OOR | closes standalone | fix task (reviewers) | fix task (after gap analysis) | top primary labels | most common Lean tactic left to Z3 | top named fixes (lines) |
|---|---|---|---|---|---|---|---|---|
| 0 (no Lean line) | 168 | 73 / 95 | 86 (51%) | translator 99 · library 25 · solver 42 · harvest 2 | — | S-RELEVANCE 63 R-NONLINEAR 39 S-INSTANTIATE 27 | — | hoist inline guarded nlinarith certificate pieces (mul_zero_eq/zero_mul_eq/sq_nonneg) into context-free cert_piece lemmas (29) emit quantified hypothesis bodies (∀, ∃, ∀-iff) through named ghost predicates/functions so they have matchable triggers (16) emit cert_piece bodies with let-bound factors, the MulPos call, and an explicit product-equality assert (12) |
| 1 | 209 | 57 / 152 | 40 (19%) | translator 82 · library 60 · solver 58 · harvest 9 | translator 81 · library 105 · solver 6 · harvest 17 | S-COMPUTE 75 S-RELEVANCE 55 T-CITE 34 | norm_num 51 · simp_all 28 · simp 24 | stop the MathPrelude pow matching loop (opaque pow with explicit PowSucc/PowAdd/PowMul lemmas instead of the recursive ensures) (35) in interval_cases/norm_num branches state the evaluated h0 instance p(k)==v and norm_num's isNat_gcd result gcd(x,y)==z (32) emit argument-free trig special-value lemmas (RealSin/CosZero, RealSin/CosPiDivTwo) for ground terms in norm_num/simp goals (8) |
| 2 | 32 | 11 / 21 | 11 (34%) | translator 9 · library 8 · solver 15 | translator 7 · library 19 · solver 2 · harvest 4 | S-RELEVANCE 15 S-COMPUTE 7 T-CITE 5 | have 9 · norm_num 6 · rw 5 | stop the MathPrelude pow matching loop (opaque pow with explicit PowSucc/PowAdd/PowMul lemmas instead of the recursive ensures) (5) instantiate named simp/norm_num hint lemmas with no recorded instance by matching their LHS against the before-goal (2) add ℚ nsmul_eq_mul and h-form Finset.sum_const at ℚ (1) |
| 3 | 26 | 7 / 19 | 11 (42%) | translator 7 · library 5 · solver 14 | translator 9 · library 13 · solver 2 · harvest 2 | S-RELEVANCE 12 T-CITE 7 S-COMPUTE 5 | have 19 · rw 2 · apply 2 | stop the MathPrelude pow matching loop (opaque pow with explicit PowSucc/PowAdd/PowMul lemmas instead of the recursive ensures) (3) map recorded Set.InjOn.eq_iff (cos on Icc 0 π, tan on Ioo) to RealInjOnCosEqIff / RealInjOnTanEqIff (2) add IntDvd-form (%-based) Mathlib dvd_add_right (1) |
| 4–5 | 34 | 18 / 16 | 7 (20%) | translator 14 · library 7 · solver 13 | — | T-CITE 12 S-RELEVANCE 6 R-NONLINEAR 5 | have 9 · norm_num 7 · rw 6 | map recorded Real.logb.eq_1 (and ground logb terms in simp/field_simp) to RealLogbUnfold (5) instantiate named simp/norm_num hint lemmas with no recorded instance by matching their LHS against the before-goal (4) add Mathlib div_eq_iff (real, Real.div form) (2) |
| 6–10 | 22 | 9 / 13 | 4 (18%) | translator 7 · library 7 · solver 8 | — | S-RELEVANCE 6 T-CITE 4 R-FIELD 4 | have 9 · simp 3 · norm_num 2 | stop the MathPrelude pow matching loop (opaque pow with explicit PowSucc/PowAdd/PowMul lemmas instead of the recursive ensures) (3) map recorded Finset.prod_pair to FinsetProdPair (1) map recorded Set.InjOn.eq_iff (cos on Icc 0 π, tan on Ioo) to RealInjOnCosEqIff / RealInjOnTanEqIff (1) |
| 11+ | 8 | 0 / 8 | 1 (12%) | translator 2 · library 5 · solver 1 | — | S-COMPUTE 4 T-LIBRARY 2 T-CITE 1 | have 5 · norm_num 1 · norm_cast 1 | stop the MathPrelude pow matching loop (opaque pow with explicit PowSucc/PowAdd/PowMul lemmas instead of the recursive ensures) (3) add Mathlib Finset.sum_singleton for ℕ-indexed/generic sets (Real.sum) (1) add Mathlib Rat.cast_injective / Rat.cast_inj with Rat.cast_neg and Rat.cast_intCast (ℚ→ℝ) (1) |
pow encoding (library) or missing translator statements. Lines with no Lean line (certificate pieces, instances, preconditions) close standalone half the time: the fact is fine, the surrounding query is too large. Blocks of 4+ lines close standalone rarely (12–20%), but there are only 64 of them.For every failing line, its extracted standalone lemma was re-checked with one kind of information Lean had added back (from Lean’s own records; ~1,810 Dafny checks, each under 30 s, never whole files). Then the smallest edit that makes Dafny prove the line was recorded. Two review passes re-ran 34 lines with controls (33 reproduced) and corrected the counts. Use the filters information kind, closing result and simplest close in the line browser below; each line’s panel shows its kinds and recipe. Strict closed versions. Every line was rebuilt as an honest standalone lemma — hypotheses = the facts Z3 had at the line minus the goal itself and minus what the step's own block (or helper lemma body) derives; proof = the file’s own proof body; then each ablation variant's additions were re-applied on top, a variant may drop hypotheses but never add one. 410 of 499 close (an earlier count of 426 included 33 lemmas whose two-line goal had been cut to its first conjunct by the builder; rebuilt with the full goal, 19 still close). In-file check. Every closed lemma was then put back into the source file at its failing line, each hypothesis re-asserted and the lemma called, and Dafny run on exactly those lines in the real context: see infile/ for the per-line table. The files are in closed/ (one per line, closed or not). Each line’s panel below shows its closed version and its in-file result. Sources: classify5/kinds/CONCLUSION.md, GUIDE.md, kinds_by_line.jsonl.
| kind of information Lean had | what it is | closes alone (discriminating, sound) | judged a cause | judged primary |
|---|---|---|---|---|
| K3 locality | Lean’s step sees one goal and a few hypotheses; Dafny checks the line against the whole method’s context | 93 | 223 | 161 |
| K2 computation | Lean computes / normalises (norm_num, ring_nf, kernel); Z3 has incomplete nonlinear arithmetic and fuel-bounded unfolding | 53 | 213 | 149 |
| K5 automation lemma | simp / norm_num / field_simp apply library lemmas silently; Z3 knows only the lemmas cited | 42 | 97 | 58 |
| K1 instance | Lean names the instance of a ∀/∃ fact; Z3 must find it by trigger matching | 27 | 85 | 71 |
| K4 types | ℕ ≥ 0, casts, ∣ ↔ % come from Lean’s types; in Dafny they are side conditions or lemmas | 13 | 47 | 31 |
| K0 none / true limit | none of the above: a true solver limit, or not about missing information | — | 36 | 29 |
*Rules measured on 499 failing lines of Lean→Dafny translations of competition proofs (integ5, 63 theorems; Dafny 4.11,
verify --isolate-assertions --resource-limit 1000000 --allow-warnings, every check in a 30 s budget). Stage k_SYNTH,
2026-10-03. Numbers: kinds/synth/tables.md, kinds/synth/greedy.txt, per line kinds/kinds_by_line.jsonl.
Analysis and caveats: kinds/CONCLUSION.md (§7 threats to validity, §9–§10 corrections after review).
Numbers were corrected after the second review (k_SKEPTIC): they count only discriminating sound closes, on lines whose lemma did not already verify unchanged. Pre-review figures are in brackets.*
A Lean proof term records five kinds of information that Z3 has to rediscover:
whole method's context.
norm_num, decide, ring_nf and the kernel evaluate and normalise. Z3 has incompletenonlinear arithmetic and unfolds recursive functions only up to a fuel bound.
simp, norm_num and field_simp apply lemmas from their databases without naming them.Z3 knows only the lemmas you call.
h 0, obtain ⟨x, hx⟩). Z3 must find instances by triggermatching (E-matching).
∣ = ∃ from its type system. In Dafny these facts must be stated asside conditions or proved with lemmas.
The rules below supply each kind of information explicitly. They are ranked by lines recovered per unit of effort.
How to read the evidence. "Closes" means the failing line's extracted lemma verified after the change.
"Of tried" is the share of lines where that change was tried. All checks are standalone lemmas, never whole files.
---
Evidence.
under the resource criterion. 142 of them also finish within 30 s on one core: 3 time out in re-runs and 4 more took
over 30 s in the dossier.
142 of the 324 OOR lines close this way.
nlinarith certificate lines: 52 of 79 close this way.Cost. Mechanical: one lemma per step plus one call. The requires are the step's hypotheses, which Lean records as
the tactic's before-state or have_deps.
Before (aime_1983_p1, line 507, fails inside a method of about 260 obligations):
assert Real.log((x as real) * (y as real)) == Real.log(x as real) + Real.log(y as real) by {
RealLogMul(x as real, y as real);
}
After (schematic: the extracted lemma that verified at 5,057 resource units carries the 23 in-scope facts as
requires, or 13 after static trimming; shown here with the two positivity facts the Lean step used):
lemma Step507(x: nat, y: nat)
requires 0.0 < x as real
requires 0.0 < y as real
ensures Real.log((x as real) * (y as real)) == Real.log(x as real) + Real.log(y as real)
{ RealLogMul(x as real, y as real); }
// in the method: Step507(x, y);
Do not rely on --isolate-assertions to provide locality. It splits obligations, but each one still carries the
whole path's facts.
pow (or any recursive function) a recursive postcondition; make it opaque and call unfolding lemmas (K2, encoding)Evidence.
Real.pow/Int.pow keeps its body but drops ensures … p == b * pow(b, k-1),or when pow/ℂ is made opaque [83]. The other 26 of the 83 either already verified standalone with nothing added
(22; there the in-file effect is plausible but not discriminated), or needed other fixes as well.
Cost. One library change, plus explicit PowSucc/PowAdd/PowMul calls wherever an unfolding is actually needed.
Before (library/MathPrelude.dfy):
function pow(b: real, k: nat): (p: real)
ensures if k == 0 then p == 1.0 else p == b * pow(b, k - 1) // re-triggers on every pow term: a matching loop
{ if k == 0 then 1.0 else b * pow(b, k - 1) }
After (recommended shape; the measured variant kept the body and only removed the recursive ensures,
kinds/work/*/_lib_nopow/_k2pow copies):
function {:opaque} pow(b: real, k: nat): real { if k == 0 then 1.0 else b * pow(b, k - 1) }
lemma PowSucc(b: real, k: nat) ensures pow(b, k + 1) == b * pow(b, k) { reveal pow(); }
General rule. A postcondition that mentions the function at a new argument is a trigger generator. Keep
recursive facts in lemmas you call. The same applies to transparent Complex.add/mul bodies, which flooded the
amc12a_2009_p15 queries.
Evidence.
included 15 lines that already verified, 10 vacuous closes in amc12a_2003_p25 (inconsistent hypotheses) and 2
multi-fix closes.
Real.sqrt_nonneg (×10), Linarith.mul_zero_eq (×8), Real.le_sqrt (×6), sin_pi_div_two/sin_zero/cos_zero/cos_pi_div_two (×10 together), div_eq_iff,
add_div' and Finset.sum_singleton.
norm_num steps the information is genuinely missing: only 2 of 72 such lines verify standalone, and 27 closewith the lemma call.
Cost. One library entry if the lemma is missing (state the exact Mathlib theorem), plus one call per use.
Before (amc12a_2021_p19, line 1726, OOR; Lean: norm_num):
assert Real.sin(Real.pi() / 2.0) == 1.0;
After (verifies):
RealSinPiDivTwo(); // Mathlib Real.sin_pi_div_two, in norm_num's simp set assert Real.sin(Real.pi() / 2.0) == 1.0;
For denominators, field_simp's work is div_eq_iff. On aime_1983_p1-1057, DivEqIffReal(24.0L, 2.0/5.0L, 60.0)
closes a line that fails even when the cleared equation is already in scope.
Evidence.
unchanged]. Examples: gcd(83, 14) = 1, 2^2012 as a numeral chain, (4k)^2 = k^2·16, Icc(-3,7) = {-3,…,7}.
norm_num/ring_nf/decide call is missing: 124 of the 209 lines with onemissing Lean line.
Cost. Per line. Take the value from Lean's records (IsNat/IsRat evaluation records, the ring_nf before- and
after-states) and assert it as a checked fact.
Before (numbertheory_aoddbdiv4asqpbsqmod8eq1, line 184, OOR even in a minimal lemma):
assert NatDvd(8, (4 * k) * (4 * k));
After (verifies):
assert 4 * k * (4 * k) == k * k * 16; // Lean ring_nf: (4k)^2 = k^2*16 assert NatDvd(8, (4 * k) * (4 * k));
In a case split, also assert the evaluated instance. In mathd_numbertheory_618 branch n = 7, either
assert p(7) == 83 or assert gcd(83, 14) == 1 closes assert false. Dafny's gcd unfolds only on literals.
Evidence.
pre-review "K1" closes were in fact the ghost-trigger rendering of Rule 8.
Cost. Per line. Lean's inst records and hint lists (linarith [h₅ 0, h₅ 1]) give the arguments.
Before (amc12a_2009_p9, line 388, fails although forall x :: xx3.0 + x(18.0+b) + (27.0+3.0b+c) == … is in
scope; Lean: linarith [h₅ 0, h₅ 1, h₅ 2, h₅ 3]):
assert 3.0 * 6.0 + b == 7.0;
After (verifies):
assert 0.0*0.0*3.0 + 0.0*(3.0*6.0 + b) + (3.0*9.0 + b*3.0 + c) == 0.0*0.0*3.0 + 0.0*7.0 + 4.0; // h₅ 0 assert 1.0*1.0*3.0 + 1.0*(3.0*6.0 + b) + (3.0*9.0 + b*3.0 + c) == 1.0*1.0*3.0 + 1.0*7.0 + 4.0; // h₅ 1 // … h₅ 2, h₅ 3 assert 3.0 * 6.0 + b == 7.0;
∣ ↔ % (K4)Evidence.
RatCastInjective (×12, ℚ→ℝ), IntMulNonneg/MulNonnegInt (×9, ℕ products in int slots), RatCastNeg (×5), IntDvdIffEmodEqZero (×3) and others.
Cost. A handful of library lemmas, each called where a cast or divisibility form changes.
Before (aime_1987_p5, line 594; h : (3(xx)+1) % 507 == 0 is in scope):
assert exists k: int :: 507 == (3 * (x * x) + 1) * k; // fails
After (verifies):
IntDvdIffEmodEqZero(3 * (x * x) + 1, 507); // Mathlib Int.dvd_iff_emod_eq_zero: in Lean ∣ *is* the ∃ assert exists k: int :: 507 == (3 * (x * x) + 1) * k;
Pick one representation for each Lean term. k^2 rendered both as Int.pow(k,2) and as k*k without a bridge
broke 4 lines.
Evidence.
ensures is literally the goal, but the arguments are compound nonlinear terms.
MulPos(xx, yy), SqPosOfNeZero(x-y) and mul_pos_of_neg_of_neg at 2x-3.assert, or as a requires, verifies.Before (algebra_bleqa_apbon2msqrtableqambsqon8b, line 33; standalone: "a precondition for this call could not be
proved", twice):
lemma Piece(x: real, y: real) requires 0.0 < x * x requires 0.0 < y * y ensures 0.0 < (x * x) * (y * y)
{ MulPos(x * x, y * y); }
After (verifies):
lemma Piece(x: real, y: real) requires 0.0 < x * x requires 0.0 < y * y ensures 0.0 < (x * x) * (y * y)
{ }
Alternatively, bind the compound term to a variable (var u := xx; var v := yy; MulPos(u, v);) and state the lemma's
conclusion about u, v.
Evidence.
amc12a_2003_p25's own hypotheses are inconsistent, so its non-vacuity rests on the reviewers' minimal lemmas. The
other three are numbertheory_fxeq…-407/-413/-442, re-filed here from K1.
Before (numbertheory_fxeq4powxp6powxp9powx_f2powmdvdf2pown, line 413; fails even with the witness asserted):
ensures exists t: nat :: n == m + t
{ assert 0 <= tsub(n, m) && n == m + tsub(n, m); }
After (verifies):
ghost function NatId(x: nat): nat { x } // identity: gives the body a trigger term
ensures exists t: nat :: n == m + NatId(t)
{ assert n == m + NatId(tsub(n, m)); }
About 9 lines judged K0, plus up to 28 lines judged computation or lemma whose every augmentation stayed failed or
OOR, involve the following:
0≤c, u<0, c·u≤0, 0<u·u, 4cu−u² = 0.
10000! % (2^5000·5000!) = 0 (amc12_2001_p5-18) and complex power sums(amc12a_2009_p15).
Do not spend solver time on these. Transfer Lean's result as checked facts small enough for Z3: the normal form,
the evaluated value, or the two Positivstellensatz products as separate asserts. imo_1965_p1-833 closed this way,
with normal-form asserts plus a mul_eq_zero lemma. Otherwise leave an honest, marked gap. Never write assume.
---
| rank | rule | lines (discriminating closes alone) [pre-review] | marginal in greedy order | effort |
|---|---|---|---|---|
| 1 | Rule 2: non-recursive / opaque pow | 57 [83] | +51 | one library edit |
| 2 | Rule 1: one lemma per step, only its facts | 176 [182] | +176 | mechanical, per step |
| 3 | Rule 6: type bridges | 31 [33] | +26 | 9 lemmas + calls |
| 4 | Rule 3: automation lemmas | 54 [81] | +63 | 47 lemmas + calls |
| 5 | Rule 7: simple lemma arguments | 16 (recovered by a plain assert) | — | rendering rule |
| 6 | Rule 8: ghost-function triggers | 10 [7] | +10 | rendering rule |
| 7 | Rule 4: computed values / normal forms | 28 [40] | +52 | per line, needs Lean's values |
| 8 | Rule 5: explicit instances | 42 [56] | +35 | per line, needs Lean's arguments |
Applying rules 1–8 together recovers 413 of 499 lines (83%) in standalone checks (sound closes only; after
the second review, CONCLUSION §10; 428 before it). That result is not yet confirmed
in-file. Rules 2, 6, 7 and 8 are one-time library or rendering decisions. Rules 3, 4 and 5 need per-line information,
which an ITP proof already contains: its tactic records.
The 267 integ5 failing lines whose corrected missing Lean block (above) is 1–3 lines were grouped into 37 clusters; for each, two independent analysts asked “why does it fail?” and “what closes it?”, one synthesis per fix task followed, and two skeptic passes per task tried to refute it. Only mechanisms the skeptics confirmed or partly confirmed are kept. Every “closes” below is a standalone Dafny check of an extracted line lemma (or a hand-built equivalent) under the corpus flags; no theorem file was re-verified, so no fix has an in-file result yet. Source: classify5/gaps/GAPS_REPORT.md (stage g3_report, 2026-10-03), shown here with its section numbers.
Scope. integ5 has 499 failing Dafny lines. This report covers the 267 of them where the Lean proof skips only 1–3 source lines at that point (gaps/lines.jsonl: 209 lines miss 1 Lean line, 32 miss 2, 26 miss 3; 192 out-of-resource, 75 errors). Three reviewers had assigned each line a fix task:
| task | lines | meaning |
|---|---|---|
| TRANSLATOR | 98 | the Lean→Dafny translator should emit something different |
| SOLVER | 87 | the facts are there, but Z3 cannot use them |
| LIBRARY | 73 | the Dafny library (MathPrelude.dfy / library_new.dfy) is missing a lemma or encodes something badly |
| HARVEST | 9 | the Lean-side record of what each tactic did is missing a fact |
How this report was produced (details in §5):
gaps/out/*.json, ~2,600 Dafny outputs under gaps/work/).gaps/task/<TASK>.md).gaps/task/<TASK>.skeptic*.md).This report keeps only the mechanisms that the skeptics confirmed or partly confirmed, and says where they corrected something.
Terms used below
requires) and goal (ensures). The "trimmed" version keeps only the hypotheses a static trimmer judged relevant.Most of the 267 lines are not hard for the solver. They fail because of a small number of systematic defects, and nearly all of them were closed in standalone experiments by fixing the defect without touching the goal.
The biggest single cause is the library's encoding of powers. This is LIBRARY.
Int.pow/Real.pow restate their own recursion as a postcondition, which makes Z3 unfold 2^n → 2^(n-1) → … endlessly. Dafny's fuel mechanism also writes the same 2^m as two different SMT terms. A second, smaller library defect: the bodies of Complex add/mul are visible, which floods the query.TRANSLATOR (98 lines). About 86 are genuine translator gaps:
gcd 691 52 = 1) and the translator wrote only a comment: 35 lines.The other 12 are not translator problems: 11 are harvest gaps and 1 is the power defect.
HARVEST (9 lines; really 23). The Lean harvester never records lemmas used as bare constants (Real.cos_zero) or wrapped by simp (_auxLemma), and it drops class-field aliases. Those three code defects explain 3 of the 9 HARVEST lines plus 12 lines labelled TRANSLATOR/LIBRARY. One added translator call closes each of them.
SOLVER (87 lines; really 10). After analysis only 10 lines are still SOLVER: true solver limits or unresolved cases.
Corrected task count: TRANSLATOR 97, LIBRARY 137, HARVEST 23, SOLVER 10 (§3).
Every mechanism below was confirmed or partly confirmed by the skeptics. "Corrected" marks a skeptic correction. Line ids are theorem-DafnyLine. "Gap set" means the 267 lines; "corpus" means all 499 failing lines or all 101 outputs.
| id | mechanism | gap lines | closed in tests | skeptic verdict |
|---|---|---|---|---|
| T1 | norm_num evaluations written as comments | 35 | 35 | holds |
| T2 | recorded lemma applications that never become a call | 10 | 8 record-backed (+285 by goal pattern, +32 half) | partly |
| T3 | lemma never recorded → moved to HARVEST | 12 | 12 | holds (root is HARVEST) |
| T4 | one object, two encodings, no bridge | 15 | 13 (452 corrected) | partly |
| T5 | rewrite stated without its justifying equality | 9 | 6 by instance + 3 by "ghost Mul" rendering | partly |
| T6 | quantifier with no usable trigger | 12 | 11 | holds |
| T7 | local step checked in the whole context | 5 | 3 (+1 partial) | partly |
Nat.gcd 691 52 = 1 or (5:ℚ)*5 = 25.isNat_gcd at exec 479 has x=691, y=52, z=1.// UNCITED-APPLIED internal ×N.gcd(691, 52) itself, but only when every argument is a literal. In the file it sees gcd(p(26), 2*26), where p is a local function.dafny_emit_v2.py:3005-3024 (the loader drops the arguments and continues); drop_sweep.py:247,636 (writes the comment); the library has no Rat.cast_injective.interval_cases:Dafny : assert false; // sub-goal of norm_num
(under the guard 1 < gcd(p(26), 2*26), with requires forall x :: p(x) == tsub(x*x,x)+41)
Lean 45: interval_cases n <;> norm_num [h₀, Nat.gcd_eq_right, …] at h₄ ⊢ -- goal: False
record : Tactic.NormNum.isNat_gcd (691, 52, z = 1)
fix : assert gcd(691, 52) == 1; // norm_num evaluation (Lean exec 479)assert <term> == <value>;. Use this only where Dafny cannot evaluate the term itself. For ℚ, add the axiom RatCastInj (= Mathlib Rat.cast_injective) and call it for each isNat_mul/isRat_mul record.gcd(691, 2*26) is OOR, while gcd(691, 52) verifies (runs s01/s02).by_contra, stays OOR even after the fix.injOn_cos.eq_iff → RealInjOnCosEqIff is therefore dead code. The same filter drops Nat.mod_mod_of_dvd, Int.card_Icc and Finset.Icc_eq_empty_of_lt.orderOf_eq_iff the ZMod modulus is inside a type. Finset.mul_sum is over a set<nat>.dafny_emit_v2.py:3009-3024 (loader); _cite_state_args :5609 / :5543 (projection).Dafny : assert (x == (Real.pi() / 2.0)) by {…}
// UNCITED-APPLIED Set.InjOn.eq_iff …: library counterpart RealInjOnCosEqIff … exists
Lean 126: apply (injOn_cos.eq_iff ⟨…⟩ ⟨…⟩).1 -- goal: x = π/2
record : Set.InjOn.eq_iff(Icc 0 π, cos, x, π/2), in_table = false (exec 1563)Nat.mod_mod_of_dvd → NatModModTotal, …).mul_sum to FinsetMulSumPointwise.rfl. Its fix (IntIccCard) is a goal-pattern guess, so it is not T2.IntIccCard is a derived axiom, not literal Mathlib. The new Real.div lemmas (div_div, div_mul_eq_mul_div, mul_div_assoc') were Lean-checked. Both need approval.| seam | Dafny side | lines |
|---|---|---|
| ℕ product rendered as an int | Dafny then asks to prove 0 <= k*Int.pow(2,n+4), which has no Lean counterpart (lean_expr_ir.py:218, _need_cast) | amc12_2001_p5-11, 3pow… 124/146/177/261/283/314 |
use w on a divisibility goal | use w only states b == a*w; Dafny's IntDvd is %-based and there is no Dvd.intro | 516 (452: see correction) |
x*x vs Real.pow(x,2) | statements unroll literal exponents to products, but cite arguments and library postconditions keep Real.pow(·,2) | 222, 530 |
Real.div vs / | LeDivIff is stated with /, the goal uses Real.div | 949 |
Irrational | the predicate is opaque; exact h ⟨2, _⟩ becomes a GAP comment | 198 |
| Icc membership vs bounds | a ∀ restatement guards with k in IccN(a,b), the facts use a <= k <= b | 212 |
| numeral cast not folded | rpow(2.0, (2 as real)*(m*n)) vs rpow(2.0, 2.0*(m*n)) are different terms | 137 |
Dafny : assert NatDvd(Int.pow(2, (n + 4)), (k * Int.pow(2, (n + 4)))) by {…}
-- the failing check is the hidden "is k*Int.pow(2,n+4) a nat?"
Lean 52: exact ⟨k, by ring⟩ -- in ℕ, so there is no sign obligation
fix : IntMulNonneg(k, Int.pow(2, n+4)); -- verified 51/0IntMulNonneg for ℕ products.IntDvdIntro/NatDvdIntro (= Mathlib Dvd.intro).LeDivIff and its 15 siblings over Real.div.NotIrrationalNatCast.h₂₁₂. In the file it is OOR, so it is a context line.Dvd.intro, Irrational.ne_rat, le_div_iff over Real.div) are exact Mathlib and were Lean-checked. They need approval.rw, ring_nf or field_simp rewrote inside a function (under √, %, /, or in a hypothesis). Dafny states the result but not the argument equality, and Z3 never connects F(e) with F(e').congrArg is dropped as "no library counterpart" (dafny_emit_v2.py:1402-1406; 1,431–1,433 such comments in 80 files, depending on the grep).@tac-hyp restatements are emitted before the execution's cites (:11747-11823).Dafny : assert NatDvd(8, ((4 * k) * (4 * k))) by {…}
Lean 38: ring_nf at * -- goal: 8 ∣ (4k)^2
fix : assert (4*k)*(4*k) == k*k*16; -- verified 12/0 (skeptic re-run)@tac-hyp asserts.Real.sqrt_one), 181.Mul(a,b), so they are really an encoding seam (T4 family). The ghost-Mul rule changes how library postconditions are rendered. Its effect on the 33,014 obligations that verify today is untested. This is the largest unquantified risk in the TRANSLATOR fixes.f(n) as a possible loop, and the side-terms it picks instead never occur at the line.lean_expr_dafny.py:556-632 (the ∃ branch never emits a trigger) and expr_render._render_quant :626-674. verify5 reports "Could not find a trigger" on each amc12a_2003_p25 line.Dafny : assert (exists x: real :: (Real.sqrt(((a * (x * x)) + (b * x))) == 0.0));
// hypothesis h₄ after simp
Lean 21: simp at h₄ h₅ h₆ h₇ h₈ -- only removes `True ↔` / `True ∧` The skeptic's minimal pair, with identical bodies:f(n) = f(n-1)+1, assert Lean's instance at each ground f(t) (rule I).{:trigger f(n)}: run s08 went OOR.have/@tac-hyp (dafny_emit_v2.py:7745, :11818). Lean's per-step dependency record (have_deps) is harvested for 102 theorems, but v2 never reads it. Only the rules emitter does, opt-in (KMAX_TRIM).Dafny : assert (-(1) + p*q*r) == … ; // hypothesis hk after ring_nf
Lean 391: ring_nf at hk ⊢
fix : a helper lemma that requires only hk, called in place — verified 7/0| id | mechanism | gap lines | closed in tests | verdict |
|---|---|---|---|---|
| L1 | power encoding (matching loop, fuel split, transparent ℂ ops) | 43 (+64–70 from SOLVER) | 30 by some variant; 15/17 under the recommended U2 | mechanism holds; fix and count partly |
| L2 | ℚ: no cast injectivity; always-on nonlinear to_real | 5 | 5 | holds |
| L3 | recorded instance has no library lemma at that type | 18 | 7 by new lemmas alone; +6 that also need L1c and translator work; +1 existing lemma | partly |
| L4 | library conclusion shaped so Z3 cannot match the goal | 5 | 5, but cleanly library only for 2 | partly |
pow makes Z3 loop (the largest mechanism in the report)2^n as an opaque value. The library defines Int.pow/Real.pow recursively and repeats the recursion as a postcondition:ensures if k == 0 then p == 1 else p == b * pow(b, k - 1) // MathPrelude.dfy:52-56, :90-96 This causes three problems:pow(2,n) produces pow(2,n-1), then pow(2,n-2), and so on, until the budget is gone.pow(2,m) as two different SMT terms, one in the goal and one in the facts. Inside cos(pow(2,m)*x), Z3 cannot see that the goal is a fact it already has.symbol_table.py:117-123, :183-191 and :540-543. The translator's use of ^ → pow is faithful.imo_1964_p1_2-95 (OOR)
Dafny: assert !(((Int.pow(2, n) + 1) % 7) == 0);
-- linear over the atom 2^n, with 2^n % 7 = 1 in scope
Lean : a simp step
Result: closes once the recursive postcondition is replaced.
numbertheory_3pow2pownm1mod2pownp3eq2pownp2-510 (OOR)
Dafny: assert NatMod(Int.pow(2,n+2) + k*Int.pow(2,n+3), Int.pow(2,n+3))
== NatMod(Int.pow(2,n+2), Int.pow(2,n+3)) by {…}
Lean 141-142: have h₂ … whose nested h₃ is the identical statement
Result: Dafny's own in-file query with only the recursive conjunct removed is unsat at 53,865
(base: unknown at 1,008,025).| variant | what it is | known good | known bad |
|---|---|---|---|
| U2 (LIBRARY synthesis) | closed forms for k ≤ 6 + {:fuel 1,1} | hoisted imo_1966_p4 block 121/123 | leaves imo_1964_p1_1-27 and imo_1966_p4-190 OOR (skeptic); fails pow(x,8)=pow(x,4)^2 |
| F33 (SOLVER synthesis) | {:fuel 3,3} + k==0 ⇒ p==1 | 0 of 12 regression probes fail | leaves amc12a_2021_p14-542/-548 and in-file 329/364 OOR |
| W33 (preferred by the SOLVER skeptic) | non-recursive wrapper over a {:fuel 3,3} recursive pow | closes 542, 548, 535, 175-107 | 1 probe regression (x^3, symbolic base); untested on the imo_1966_p4 block |
assume. Recommendation. Remove the recursive postcondition, adopt W33 or F33 plus emitting the existing PowSucc/IntPowSucc cites where Lean's ring normal form has pow(b,k+1), then decide by a whole-corpus run. A whole-corpus run is the only way to measure regressions, and it was not allowed here.Real.pow postcondition: a standalone check gives 136 verified and 1 error at :55. Nobody sees this, because included files are not verified. Both skeptics confirmed it.Complex.add/mul/of_real, not Complex.pow (refuted in three lenses).symbol_table.py plus ~30 for ℂ. Needs the user's corpus re-verify before adoption.Rat.cast_injective. Dafny's ℚ operations are known only through their real value. A second layer: an always-on nonlinear postcondition to_real == num/denom on every ℚ term.Dafny : assert (u(0) == Rat.add(u(0), Rat.of_int(0)))
Lean 16: norm_num -- internally add_zero It closes with RatCastInj.RatCastInj.to_real postcondition.Rat.of_int/Rat.neg axiom functions with the exact Mathlib statements. Seven statements were Lean-checked (rc 0).RatCastInj(lhs, rhs) before each ℚ equality, and make the ring-identity exemption sort-aware.to_real's postcondition is gone.Finset.sum_singleton exists only for ℝ and ℤ, but every recorded use is at ℕ. Also missing: Nat.gcd_self_add_right, and Complex.re_sum/im_sum/ofReal_mul.Dafny: assert Real.sum(IccN(2,2), k => 2.0*(Real.sqrt(k as real) - …))
== 2.0*(Real.sqrt(2 as real) - Real.sqrt(1.0))
Lean : norm_num, internally Finset.Icc_self + Finset.sum_singleton at ℕ Adding FinsetSumSingletonNat closes it (trimmed 8/0, original 14/0).in_table at emit time instead of freezing it at harvest time.FinsetSumAddDistribRat concludes about the lambda x => Rat.add(f(x),g(x)), and Dafny lambdas are not extensional.Dafny : assert Rat.sum(range(98), k => Rat.add(u(0), …)) == Rat.add(Rat.sum(range(98), k => u(0)), …)
Lean 43: rw [Finset.sum_add_distrib]
fix : the proved twin FinsetSumAddDistribRatH(s, h, f, g), called with the goal's own lambda — closesDo not adopt as written. The skeptic found that the analyst axiom NatAddMulModSelfLeft is ill-formed: it is a possible division by zero. Nobody saw this, because included files are not checked. It is not in any recommended fix.
The SOLVER label turned out to be mostly a symptom label. In 81 of the 87 lines Z3 is not missing a fact; a library or translator defect makes the query expensive.
| id | mechanism | lines | where it really belongs | tested |
|---|---|---|---|---|
| S-M1 | power encoding (= L1) | 62 | LIBRARY (60; 156/187 stay SOLVER) | 57 shown closed, by Dafny or in-file replay (skeptic: not 58; fxeq-318 timed out under F33) |
| S-M2 | transparent Complex arithmetic (= L1c) | 11 | LIBRARY | 7 closed, 3 partial, 1 untestable |
| S-M3 | a cite's conclusion is stated over call temporaries | 3 → 2 | TRANSLATOR | 2; 803 corrected → S-M4 |
| S-M4 | monolithic procedure (= T7) | 0 → 1 primary (803) | TRANSLATOR | tested alternative fix for 9 more |
| S-M5 | ground evaluation Lean did by kernel/simprocs | 6 | LIBRARY+TRANSLATOR (4), none (2) | 4 |
| S-M6 | output shape hides in-scope facts (if-guarded cert pieces) | 3 | TRANSLATOR | 569/656 standalone; 698 only as a hand-placed cite |
| S-M7 | genuine solver residue | 2 | SOLVER | 0 |
Skeptic corrections.
Int.pow(16,502).S-M3 example. algebra_abpbcpcageq3_sumaonsqrtapbgeq3onsqrt2-1725:
Dafny : assert (2.0*Real.sqrt(2.0)) * (…sum…) >= (2.0*Real.sqrt(2.0)) * (3.0/4.0) by {…gcongr…}
Lean 146-148: gcongr <;> linarith
gcongr_mul_le_mul_left(3/4, S, 2*sqrt 2) fails, even though its conclusion is the goal verbatim. Dafny binds the arguments to temporaries, so the conclusion is "temp × temp". Dafny 4.11 also forces Z3's legacy arithmetic solver.S-M6 example. amc12b_2020_p21-569:
Dafny : assert ((k as real)+15.0)*((k as real)+15.0) <= (n as real)
Lean 74-75: nlinarith [Real.sq_sqrt …, h₉]
if (premise), even though the premise is a hypothesis.| id | mechanism | gap lines | closed firmly | verdict |
|---|---|---|---|---|
| H1 | class-field aliases (eq_zero_or_eq_zero_of_mul_eq_zero) dropped by the projection filter | 3 | 2 (205 already closes without the cite) | holds |
| H2 | hypothesis-side rewrites not in the record files (90 of 100 predate harvest4) | 5 | 1 (756, and only with a translator reorder) | partly |
| H3 | instances of a "for all" hypothesis hidden behind Eq.mp casts | 1 | 1 | holds (single line; the walker miss is inferred) |
| H4 | bare theorem constants (Real.cos_zero) never recorded | 8 | 7 (+1733 in a hand-built lemma) | holds (strongest) |
| H5 | simp _auxLemma wrappers of hint lemmas dropped as internal | 3 → 4 | 2 (+1485 own lemma; +495 with LIBRARY) | holds, under-counted |
cos 0 = 1, sin 0 = 0, cos(π/2) = 0, sin(π/2) = 1. The library has all of them (RealCosZero(), …), but they are called 0 times in all 101 outputs.harvest_goal_states.py:631: the catch-all | _ => pure ().Dafny : assert (Real.cos(x) == Real.cos(0.0));
Lean 154: norm_num [h₅₁₅₄] -- goal: cos x = cos 0; the proof term contains bare Real.cos_zero
fix : RealCosZero(); -- 29/0; without it: 28 verified, 1 errorRealSinPiDivTwo() on line 1722) does not close the line. The fix is specific, not "any extra axiom".sin(π/2) appears only after rewriting. That is why the fix belongs in the harvest, not in a translator guess..const case in walkT that emits a zero-argument record. The existing translator path then cites it._auxLemma hides the user's hint lemmaDafny : assert (20 as real) <= Real.sqrt(400.0)
Lean 258: norm_num [Real.le_sqrt, Real.sqrt_lt]
-- simp wraps the hint as _auxLemma.1 := propext (Real.le_sqrt …)
fix : RealLeSqrt(20.0, 400.0) -- 8/0; control: 1 error_auxLemmas come from dvd_add_right and from a Mathlib-module simp lemma (dvd_mul_left). So the fix must also unfold Mathlib-module _auxLemmas, not only the user's hints._auxLemma.N, unfold it to the underlying theorem with its arguments.Dafny: assert ((x*x-2.0)==0.0) || ((x*x-3.0)==0.0)
Lean : apply eq_zero_or_eq_zero_of_mul_eq_zero h₇₂
NoZeroDivisors.eq_zero_or_eq_zero_of_mul_eq_zero, which the harvester filters as a "projection".Facts.
@tac-hyp asserts and 54 failing @tac-hyp lines.Re-harvesting alone closes none of the 5 lines.
Dafny: assert (a*Real.log(2.0)) == Real.log(32.0); // h₄ after rw
Lean : rw [Real.log_rpow …] at h₄ The cite is in the file, 3 lines too late. The skeptic found that the record is mis-attributed to a later execution, not absent. Closing the line also needs a translator rule: emit cites before the @tac-hyp restatement.linarith [h₅ 0, h₅ 1, …] after simp_all produces Eq.mp … h₅ 0. The harvester's instance test needs a bare hypothesis head, so nothing is recorded.h₅ 0 and h₅ 1 closes the line.The script gaps/g3_corrected_tasks.py writes gaps/corrected_tasks.jsonl (one row per line, with the reason). Every move comes from a synthesis or skeptic finding cited above.
| consensus ↓ / corrected → | TRANSLATOR | LIBRARY | SOLVER | HARVEST | total |
|---|---|---|---|---|---|
| TRANSLATOR | 86 | 1 (imo_1966_p4-174, power loop) | 0 | 11 (H4 ×8, H5 ×3) | 98 |
| LIBRARY | 4 (p18-140/192 existing lemma; 462 existing lemma; p6-28) | 62 | 4 (1801, 546, p15-45, p15-183) | 3 (p15-496/537, 495) | 73 |
| SOLVER | 7 (507, 1725, 803, 569, 656, 698, 175-93) | 74 (60 power, 11 Complex, 31, 192, 484) | 6 | 0 | 87 |
| HARVEST | 0 | 0 | 0 | 9 | 9 |
| corrected total | 97 | 137 | 10 | 23 | 267 |
Lines needing more than one task. Primary task first, with the co-fix in brackets.
Interpretation. The consensus over-counted SOLVER by a factor of almost 9. Most "Z3 gives up" lines were caused by the library's power encoding. LIBRARY becomes the largest task, but it is dominated by one edit.
(The reviewers' change list for all 499 lines is the ranked fix list above.) Ranked by lines closed with evidence ÷ effort. "Approval" is needed for every new axiom and for any change whose regression risk can only be measured by a whole-corpus re-verify (which this stage was not allowed to run).
| # | fix (task) | gap lines it addresses | evidence of closing (standalone) | corpus beyond the gap set | effort | needs user approval? |
|---|---|---|---|---|---|---|
| 1 | Remove the recursive pow postcondition, equalise fuel (W33 or F33), and emit PowSucc cites (LIBRARY) | ≈ 104 (43 L1 + 60 S-M1 + 174; overlaps with others) | 57/62 S-M1 + 30/43 L1, by some variant; the best single variant is not yet known | 104/499 close in in-file replay | small edit + corpus re-verify | yes: corpus re-verify; variant choice |
| 2 | Transcribe norm_num evaluation records as checked asserts, + RatCastInj (TRANSLATOR T1 + LIBRARY L2) | 35 + 5 + 12 related | 35/35; L2 5/5; +12 with RatCastInj | ≤ 63 lines carry such records (untested) | small–medium | yes for RatCastInj (exact Mathlib, Lean-checked) |
| 3 | Harvester: record bare constants, unfold _auxLemma, alias map (HARVEST H4, H5, H1) | 8 + 4 + 3 = 15 | 7 + 2(+2 caveat) + 2 firm | +4 amc12b_2020_p21; 96 nullary notes; 898 "arguments unknown" | small + re-harvest | no (existing exact axioms) |
| 4 | Opaque Complex add/mul/of_real with proved postconditions + reveal rule (LIBRARY) | 11 (+6 L3 lines that need it) | 7 closed, 3 partial | 10 more close in replay | small | yes: corpus re-verify |
| 5 | Ghost-function lifting of quantifier bodies + Lean-instance rule I (TRANSLATOR T6) | 12 | 11 | 84 no-trigger warnings / 17 files | medium | no |
| 6 | Encoding bridges at the seven seams (TRANSLATOR T4) | 15 (13 genuine) | 13 | 459 nat-slot products, 14 failing lines | medium | yes: Dvd.intro, Irrational.ne_rat, Real.div-form lemmas |
| 7 | Loader admits recorded internal/aliased lemmas + argument adapters (TRANSLATOR T2) | 10 (+imo_1959_p1-32) | 8 | 12,827 dropped internal records (most glue) | small–medium | yes: IntIccCard, Real.div lemmas |
| 8 | New library lemmas at the missing types (LIBRARY L3) + proved twins (L4) | 18 + 5 | 7 alone (+6 with #4); L4 5 | 9 not-expressible sum_singleton comments | small each | yes (axioms); twins no |
| 9 | Rewrite-step equalities, cites before @tac-hyp, ∀-instances (TRANSLATOR T5) | 9 | 6 (+3 needing ghost Mul) | 1,431–1,433 dropped congrArg comments | medium | ghost Mul: yes, corpus re-verify |
| 10 | Unconditional cert pieces, norm_cast cites, cites as function postconditions (TRANSLATOR, ex-SOLVER M3/M6) | 2 + 3 | 569, 656, 1725, 507 (contested) | 466 guarded calls / 37 files; 566 temp-bound cites | small–medium | no |
| 11 | Lean-footprint scoped emission, have_deps → helper lemmas (TRANSLATOR T7 / S-M4) | 5 + 803 + context lines | 488, 5471, 803; alternative fix for 9 c013 lines | 160 failing lines close standalone | large | yes: completeness cost (29→18 on the rules track) |
| 12 | Re-run harvest4 on 90 theorems + record for amc12a_2019_p21 + cite ordering (HARVEST H2) | 5 (+~10 needing it) | 1 (756 with reorder) | ≈ 60 lines with a harvest-blind note | ~1 rack-hour + small translator change | no |
| 13 | ℚ sum_range_succ + isolated per-step replay; goal-matched NatPowMod (ex-SOLVER M5) | 3 | 192, 484, 93 | 18 lines with large numeral sums | small | yes (axioms; 93 is goal-matched, not record-backed) |
Fix before anything else (infrastructure).
Real.pow postcondition at :55 fails under --isolate-assertions (136 verified, 1 error), while the prelude verifies with Dafny's default flags (51 verified, 0 errors). The postcondition is true, so this is a proof-checking gap, not a false axiom. Fix #1 removes that postcondition.false /*VC_GAP*/.vc_extract --names source renames call temporaries, which hides S-M3.The 10 lines left as SOLVER:
| line | why it stays | is it a true solver limit? |
|---|---|---|
| amc12_2001_p5-18, -53 | Lean's rfl makes the kernel evaluate 10000! mod (2^5000·5000!) and a product of 5000 odd numbers. Dafny/Z3 has no faithful way to do that computation. | yes: kernel evaluation of a huge ground term |
| imo_1966_p4-156, -187 | With the power fix, the in-file query turns from OOR into a fast incomplete (theory arithmetic). Nothing tested closes them in-file. | yes, probably: nonlinear residue (they close standalone in every library) |
| imo_1974_p5-1801 | All 12 recorded field_simp instances supplied: still OOR | probably: products in divisors |
| amc12b_2021_p9-546 | Recorded sub_div' instances fail; only an unrecorded div_sub_div_same matched by goal shape closes it | solver limit for Lean's route; a translator goal-shape rule would close it at the cost of record-faithfulness |
| amc12a_2009_p15-45 | ℂ equation goal; needs a ℂ "peel" Lean did not record as such | open |
| amc12a_2009_p15-183 | OOR with all ℂ facts until the mod identity is a separate helper | partly context; open |
| amc12b_2020_p13-452 | needs √a·√b = 1 by a degree-4 argument; a non-Lean assert chain closes it, but that would be invented | not established: the skeptic found Lean's nlinarith certificate only partly emitted (some pieces "not stated", the rest under if). Emitting all recorded pieces is untested |
| imo_1984_p2-1685 | one lens closes it in place with {:fuel 1,1}; the other finds its raw query unsat alone | unknown: the in-file failure is not reproducible from the query |
Cross-cutting solver setting.
smt.arith.solver 2) and drops a user override.arith.solver 6 flips 202; 104 lines close fully (18 of them task lines); 21 queries regress.Bottom line. About 4–6 of the 267 lines (2%) look like real solver limits. The rest are pipeline defects with tested repairs.
What was done.
gaps/work/ and gaps/task/*runs*.Flags. Every Dafny check used dafny verify --isolate-assertions --resource-limit 1000000 --allow-warnings --cores 2 with Dafny 4.11 (~/opt/dafny/dafny), the corpus flag set. Some checks also used --filter-symbol.
Skeptic run counts.
| task | skeptic Dafny runs | other checks |
|---|---|---|
| TRANSLATOR | 12 + 20 | contract_diff check |
| LIBRARY | 20 | |
| SOLVER | 10 + 18 | |
| HARVEST | 14 + 10 | 1 Lean proof-term probe |
What "closes" means here. One standalone Dafny check of a line lemma (original or trimmed), a hand-built minimal lemma, or a hoisted helper.
assume was used.lake env lean in ~/mathlib410). They were not re-checked in this stage.What was NOT done, by rule or for lack of budget.
Why "closes standalone" is weaker than it sounds.
Open contradictions (carried, not resolved here).
Files.
gaps/GAPS_REPORT.md (this file) and gaps/GAPS_REPORT.html (same content, self-contained, not published).gaps/corrected_tasks.jsonl, written by gaps/g3_corrected_tasks.py.gaps/task/*.md|json, gaps/out/*.json, gaps/lines.jsonl, SUMMARY.md, BLOCKSIZE*.md.| theorem | line | kind | statement | primary (votes) | task | missing Lean lines | Lean had (kind) | closed by (strict) |
|---|