Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: check function types when detecting congruences in grind #6466

Merged
merged 3 commits into from
Dec 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/Lean/Meta/Tactic/Grind/Internalize.lean
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,18 @@ namespace Lean.Meta.Grind
/-- Adds `e` to congruence table. -/
def addCongrTable (e : Expr) : GoalM Unit := do
if let some { e := e' } := (← get).congrTable.find? { e } then
-- `f` and `g` must have the same type.
-- See paper: Congruence Closure in Intensional Type Theory
let f := e.getAppFn
let g := e'.getAppFn
unless isSameExpr f g do
unless (← hasSameType f g) do
trace[grind.issues] "found congruence between{indentExpr e}\nand{indentExpr e'}\nbut functions have different types"
return ()
trace[grind.congr] "{e} = {e'}"
pushEqHEq e e' congrPlaceholderProof
-- TODO: we must check whether the types of the functions are the same
-- TODO: update cgRoot for `e`
let node ← getENode e
setENode e { node with cgRoot := e' }
else
modify fun s => { s with congrTable := s.congrTable.insert { e } }

Expand Down
9 changes: 8 additions & 1 deletion src/Lean/Meta/Tactic/Grind/Inv.lean
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,16 @@ private def checkEqc (root : ENode) : GoalM Unit := do
size := size + 1
-- The root of `curr` must be `root`
assert! isSameExpr (← getRoot curr) root.self
-- Check congruence root
if curr.isApp then
if let some { e } := (← get).congrTable.find? { e := curr } then
if (← hasSameType e.getAppFn curr.getAppFn) then
assert! isSameExpr e (← getENode curr).cgRoot
else
assert! isSameExpr curr (← getENode curr).cgRoot
-- If the equivalence class does not have HEq proofs, then the types must be definitionally equal.
unless root.heqProofs do
assert! (← withDefault <| isDefEq (← inferType curr) (← inferType root.self))
assert! (← hasSameType curr root.self)
-- Starting at `curr`, following the `target?` field leads to `root`.
let mut n := curr
repeat
Expand Down
2 changes: 1 addition & 1 deletion src/Lean/Meta/Tactic/Grind/Proof.lean
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ where
trace[grind.proof] "{a} = {b}"
mkEqProofCore a b (heq := false)
else
if (← withDefault <| isDefEq (← inferType a) (← inferType b)) then
if (← hasSameType a b) then
trace[grind.proof] "{a} = {b}"
mkEqOfHEq (← mkEqProofCore a b (heq := true))
else
Expand Down
6 changes: 5 additions & 1 deletion src/Lean/Meta/Tactic/Grind/Types.lean
Original file line number Diff line number Diff line change
Expand Up @@ -356,8 +356,12 @@ Otherwise, it pushes `HEq lhs rhs`.
def pushEqCore (lhs rhs proof : Expr) (isHEq : Bool) : GoalM Unit :=
modify fun s => { s with newEqs := s.newEqs.push { lhs, rhs, proof, isHEq } }

/-- Return `true` if `a` and `b` have the same type. -/
def hasSameType (a b : Expr) : MetaM Bool :=
withDefault do isDefEq (← inferType a) (← inferType b)

@[inline] def pushEqHEq (lhs rhs proof : Expr) : GoalM Unit := do
if (← withDefault <| isDefEq (← inferType lhs) (← inferType rhs)) then
if (← hasSameType lhs rhs) then
pushEqCore lhs rhs proof (isHEq := false)
else
pushEqCore lhs rhs proof (isHEq := true)
Expand Down
18 changes: 18 additions & 0 deletions tests/lean/run/grind_pre.lean
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,21 @@ example (a b : Nat) (f : Nat → Nat) : (h₁ : a = b) → (h₂ : f a ≠ f b)

example (a : α) (p q r : Prop) : (h₁ : HEq p a) → (h₂ : HEq q a) → (h₃ : p = r) → q = r := by
grind

/--
warning: declaration uses 'sorry'
---
info: [grind.issues] found congruence between
g b
and
f a
but functions have different types
-/
#guard_msgs in
set_option trace.grind.issues true in
set_option trace.grind.proof.detail false in
set_option trace.grind.proof false in
set_option trace.grind.pre false in
example (f : Nat → Bool) (g : Int → Bool) (a : Nat) (b : Int) : HEq f g → HEq a b → f a = g b := by
fail_if_success grind
sorry
Loading