This PR simplifies the `grind` canonicalizer by removing dead state and unnecessary complexity, and fixes two bugs discovered during the cleanup. ## Changes **Canonicalizer cleanup:** - Remove dead `Canon.State.canon` field — values were inserted but never read. The canonicalizer uses a transient `HashMap` local to each `canonImpl` invocation. - Remove `proofCanon` — it deduplicated `Grind.nestedProof` terms by mapping canonicalized propositions to a single representative, but different proofs may reference different hypotheses, making the result context-dependent and preventing cache sharing across goals. - Remove `isDefEqBounded` — a fallback that retried `isDefEq` at default transparency with a heartbeat budget. The one test that depended on it was actually masking a transparency bug in `propagateCtorHomo`. **Bug fixes:** - Use `withDefault` for `mkAppOptM` in `propagateCtorHomo` (`Ctor.lean`) — the injectivity proof construction needs default transparency to unify implicit arguments of indexed inductive types like `Vector`. - Add `Grind.abstractFn` gadget to protect lambda abstractions created by `abstractGroundMismatches?` from beta reduction during preprocessing. Without this, `Core.betaReduce` in `preprocessLight` collapses `(fun x => body) arg` back to `body[arg/x]`, undoing the abstraction that congruence closure needs. **Eta reduction infrastructure:** - Lower `etaReduceAll` from `MetaM` to `CoreM` — it only performs structural operations, no `MetaM` needed. - Add `etaReduceWithCache` that takes and returns an explicit `HashMap` cache, enabling callers to thread a single cache across multiple expressions. The net effect on `Canon.State` is removing 3 fields (`canon`, `proofCanon`) and the `isDefEqBounded` function, along with the `useIsDefEqBounded` and `parent` parameters from `canonElemCore`. --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
22 lines
755 B
Text
22 lines
755 B
Text
import Std.Data.ExtHashMap
|
|
open Std
|
|
set_option warn.sorry false
|
|
|
|
-- Without `proofCanon`, two `m[k]` appear because they carry different proofs.
|
|
/--
|
|
trace: [grind.lia.model] k := 101
|
|
[grind.lia.model] (ExtHashMap.filter (fun k x => decide (101 ≤ k)) (m.insert 1 3))[k] := 4
|
|
[grind.lia.model] (m.insert 1 2)[k] := 4
|
|
[grind.lia.model] (m.insert 1 3)[k] := 4
|
|
[grind.lia.model] m[k] := 4
|
|
[grind.lia.model] m[k] := 4
|
|
[grind.lia.model] (m.insert 1 2).getKey k ⋯ := 101
|
|
[grind.lia.model] m.getKey k ⋯ := 101
|
|
-/
|
|
#guard_msgs in
|
|
example (m : ExtHashMap Nat Nat) :
|
|
(m.insert 1 2).filter (fun k _ => k > 1000) = (m.insert 1 3).filter fun k _ => k > 100 := by
|
|
ext1 k
|
|
set_option trace.grind.lia.model true in
|
|
fail_if_success grind (splits := 4)
|
|
sorry
|