fix: disequality proof construction in grind (#9578)

This PR fixes an issue in `grind`'s disequality proof construction. The
issue occurs when an equality is merged with the `False` equivalence
class, but it is not the root of its congruence class, and its
congruence root has not yet been merged into the `False` equivalence
class yet.

closes #9562
This commit is contained in:
Leonardo de Moura 2025-07-27 16:49:10 +02:00 committed by GitHub
parent d7e7bd16a6
commit 7034310a3b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 31 additions and 2 deletions

View file

@ -335,8 +335,25 @@ where
propagateCommRing ringTodo
propagateLinarith linarithTodo
updateRoots (lhs : Expr) (rootNew : Expr) : GoalM Unit := do
traverseEqc lhs fun n =>
setENode n.self { n with root := rootNew }
let isFalseRoot ← isFalseExpr rootNew
traverseEqc lhs fun n => do
let n := { n with root := rootNew }
setENode n.self n
/-
If `n` is an equality being inserted into the `False` equivalence class,
we must ensure it is root `m` of its congruence class if the root is not already
in the `False` equivalence class.
This can happen when the equality `n = m` is still has to be processed. That is,
it is in the `newFacts` todo array.
A similar swap is performed at `addCongrTable`.
-/
if isFalseRoot && n.self.isAppOfArity ``Eq 3 && !n.isCongrRoot then
if let some { e } := (← get).congrTable.find? { e := n.self } then
-- If the current congruence root is already `False`, we don't need to swap
unless (← isFalseExpr e) do
-- We must swap the congruence root to ensure `isDiseq` and `getDiseqFor?` work properly
modify fun s => { s with congrTable := s.congrTable.insert { e := n.self } }
setENode n.self { n with congr := n.self }
/-- Ensures collection of equations to be processed is empty. -/
private def resetNewFacts : GoalM Unit :=

View file

@ -0,0 +1,12 @@
axiom A : Type
axiom angle (x y z : A) : Int
axiom pi : Int
axiom Collinear (x y z : A) : Prop
axiom collinear_iff_eq_or_eq_or_angle_eq_zero_or_angle_eq_pi {p₁ p₂ p₃ : A} :
Collinear p₁ p₂ p₃ ↔ p₁ = p₂ p₃ = p₂ angle p₁ p₂ p₃ = 0 angle p₁ p₂ p₃ = pi
example {a b c a' b' c' : A} (h : ¬Collinear a b c)
(ha₁ : angle a b c = angle a' b' c')
(h' : angle a' b' c' = 0 angle a' b' c' = pi) :
False := by
grind only [collinear_iff_eq_or_eq_or_angle_eq_zero_or_angle_eq_pi]