Skip to content

Commit 6881177

Browse files
authored
feat: grind order negative constraints (#10600)
This PR implements support for negative constraints in `grind order`. Examples: ```lean open Lean Grind example [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsLinearPreorder α] (a b c d : α) : a ≤ b → ¬ (c ≤ b) → ¬ (d ≤ c) → d < a → False := by grind -linarith (splits := 0) example [LE α] [Std.IsLinearPreorder α] (a b c d : α) : a ≤ b → ¬ (c ≤ b) → ¬ (d ≤ c) → ¬ (a ≤ d) → False := by grind -linarith (splits := 0) example [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsLinearPreorder α] [CommRing α] [OrderedRing α] (a b c d : α) : a - b ≤ 5 → ¬ (c ≤ b) → ¬ (d ≤ c + 2) → d ≤ a - 8 → False := by grind -linarith (splits := 0) ```
1 parent 409daac commit 6881177

File tree

7 files changed

+107
-14
lines changed

7 files changed

+107
-14
lines changed

src/Init/Grind/Order.lean

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,17 @@ import Init.Grind.Ring
1010
public section
1111
namespace Lean.Grind.Order
1212

13+
attribute [local instance] Ring.intCast
14+
1315
/-!
1416
Helper theorems to assert constraints
1517
-/
1618
theorem eq_mp {p q : Prop} (h₁ : p = q) (h₂ : p) : q := by
1719
subst p; simp [*]
1820

21+
theorem eq_mp_not {p q : Prop} (h₁ : p = q) (h₂ : ¬ p) : ¬ q := by
22+
subst p; simp [*]
23+
1924
theorem eq_trans_true {p q : Prop} (h₁ : p = q) (h₂ : q = True) : p = True := by
2025
subst p; simp [*]
2126

@@ -29,24 +34,24 @@ theorem eq_trans_false' {p q : Prop} (h₁ : p = q) (h₂ : p = False) : q = Fal
2934
subst p; simp [*]
3035

3136
theorem le_of_eq {α} [LE α] [Std.IsPreorder α]
32-
(a b : α) : a = b → a ≤ b := by
37+
{a b : α} : a = b → a ≤ b := by
3338
intro h; subst a; apply Std.IsPreorder.le_refl
3439

3540
theorem le_of_not_le {α} [LE α] [Std.IsLinearPreorder α]
36-
(a b : α) : ¬ a ≤ b → b ≤ a := by
41+
{a b : α} : ¬ a ≤ b → b ≤ a := by
3742
intro h
3843
have := Std.IsLinearPreorder.le_total a b
3944
cases this; contradiction; assumption
4045

4146
theorem lt_of_not_le {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsLinearPreorder α]
42-
(a b : α) : ¬ a ≤ b → b < a := by
47+
{a b : α} : ¬ a ≤ b → b < a := by
4348
intro h
4449
rw [Std.LawfulOrderLT.lt_iff]
4550
have := Std.IsLinearPreorder.le_total a b
4651
cases this; contradiction; simp [*]
4752

4853
theorem le_of_not_lt {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsLinearPreorder α]
49-
(a b : α) : ¬ a < b → b ≤ a := by
54+
{a b : α} : ¬ a < b → b ≤ a := by
5055
rw [Std.LawfulOrderLT.lt_iff]
5156
open Classical in
5257
rw [Classical.not_and_iff_not_or_not, Classical.not_not]
@@ -56,8 +61,26 @@ theorem le_of_not_lt {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsLinearPr
5661
cases this; contradiction; assumption
5762
next => assumption
5863

59-
theorem int_lt {x y k : Int} : x < y + k → x ≤ y + (k-1) := by
60-
omega
64+
theorem le_of_not_lt_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsLinearPreorder α] [Ring α] [OrderedRing α]
65+
{a b : α} {k k' : Int} : k'.beq' (-k) → ¬ a < b + k → b ≤ a + k' := by
66+
simp; intro _ h; subst k'
67+
replace h := le_of_not_lt h
68+
replace h := OrderedAdd.add_le_left h (-k)
69+
rw [Semiring.add_assoc, AddCommGroup.add_neg_cancel, Semiring.add_zero] at h
70+
rw [Ring.intCast_neg]
71+
assumption
72+
73+
theorem lt_of_not_le_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsLinearPreorder α] [Ring α] [OrderedRing α]
74+
{a b : α} {k k' : Int} : k'.beq' (-k) → ¬ a ≤ b + k → b < a + k' := by
75+
simp; intro _ h; subst k'
76+
replace h := lt_of_not_le h
77+
replace h := OrderedAdd.add_lt_left h (-k)
78+
rw [Semiring.add_assoc, AddCommGroup.add_neg_cancel, Semiring.add_zero] at h
79+
rw [Ring.intCast_neg]
80+
assumption
81+
82+
theorem int_lt {x y k k' : Int} : k'.beq' (k-1) → x < y + k → x ≤ y + k' := by
83+
simp; intro; subst k'; omega
6184

6285
/-!
6386
Helper theorem for equality propagation
@@ -89,8 +112,6 @@ theorem lt_unsat {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α]
89112
Transitivity with offsets
90113
-/
91114

92-
attribute [local instance] Ring.intCast
93-
94115
theorem le_trans_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
95116
{a b c : α} {k₁ k₂ : Int} (k : Int) (h₁ : a ≤ b + k₁) (h₂ : b ≤ c + k₂) : k == k₂ + k₁ → a ≤ c + k := by
96117
intro h; simp at h; subst k

src/Lean/Meta/Tactic/Grind/Order/Assert.lean

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,39 @@ def assertIneqTrue (c : Cnstr NodeId) (e : Expr) (he : Expr) : OrderM Unit := do
226226
/--
227227
Asserts constraint `c` associated with `e` where `he : e = False`.
228228
-/
229-
def assertIneqFalse (c : Cnstr NodeId) (_e : Expr) (_he : Expr) : OrderM Unit := do
229+
def assertIneqFalse (c : Cnstr NodeId) (e : Expr) (he : Expr) : OrderM Unit := do
230+
unless (← isLinearPreorder) do return ()
230231
trace[grind.order.assert] "¬ {← c.pp}"
232+
let h ← if let some h := c.h? then
233+
pure <| mkApp4 (mkConst ``Grind.Order.eq_mp_not) e c.e h (mkOfEqFalseCore e he)
234+
else
235+
pure <| mkOfEqFalseCore e he
236+
if (← isRing) then
237+
let declName := if c.kind matches .lt then
238+
``Grind.Order.le_of_not_lt_k
239+
else
240+
``Grind.Order.lt_of_not_le_k
241+
let h' ← mkLinearOrdRingPrefix declName
242+
let mut k' := -c.k
243+
let mut h := mkApp6 h' (← getExpr c.u) (← getExpr c.v) (toExpr c.k) (toExpr k') eagerReflBoolTrue h
244+
let mut strict := c.kind matches .le
245+
if (← isInt) && strict then
246+
h := mkApp6 (mkConst ``Grind.Order.int_lt) (← getExpr c.v) (← getExpr c.u) (toExpr k') (toExpr (k'-1)) eagerReflBoolTrue h
247+
k' := k' - 1
248+
strict := !strict
249+
addEdge c.v c.u { k := k', strict } h
250+
else if c.kind matches .lt then
251+
let h' ← mkLeLtLinearPrefix ``Grind.Order.le_of_not_lt
252+
let h := mkApp3 h' (← getExpr c.u) (← getExpr c.v) h
253+
addEdge c.v c.u { strict := false } h
254+
else if (← hasLt) then
255+
let h' ← mkLeLtLinearPrefix ``Grind.Order.lt_of_not_le
256+
let h := mkApp3 h' (← getExpr c.u) (← getExpr c.v) h
257+
addEdge c.v c.u { strict := true } h
258+
else
259+
let h' ← mkLeLinearPrefix ``Grind.Order.le_of_not_le
260+
let h := mkApp3 h' (← getExpr c.u) (← getExpr c.v) h
261+
addEdge c.v c.u { strict := false } h
231262

232263
def getStructIdOf? (e : Expr) : GoalM (Option Nat) := do
233264
return (← get').exprToStructId.find? { expr := e }

src/Lean/Meta/Tactic/Grind/Order/Internalize.lean

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,6 @@ def internalizeCnstr (e : Expr) (kind : CnstrKind) (lhs rhs : Expr) : OrderM Uni
209209
s.cnstrsOf.insert (u, v) cs
210210
}
211211

212-
def hasLt : OrderM Bool :=
213-
return (← getStruct).ltFn?.isSome
214-
215212
open Arith.Cutsat in
216213
def adaptNat (e : Expr) : GoalM Expr := do
217214
let (eNew, h) ← match_expr e with

src/Lean/Meta/Tactic/Grind/Order/OrderM.lean

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,13 @@ def isRing : OrderM Bool :=
6060
def isPartialOrder : OrderM Bool :=
6161
return (← getStruct).isPartialInst?.isSome
6262

63+
def isLinearPreorder : OrderM Bool :=
64+
return (← getStruct).isLinearPreInst?.isSome
65+
66+
def hasLt : OrderM Bool :=
67+
return (← getStruct).lawfulOrderLTInst?.isSome
68+
69+
def isInt : OrderM Bool :=
70+
return isSameExpr (← getStruct).type (← getIntExpr)
71+
6372
end Lean.Meta.Grind.Order

src/Lean/Meta/Tactic/Grind/Order/Proof.lean

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ public def mkLeLtLinearPrefix (declName : Name) : OrderM Expr := do
4444
let s ← getStruct
4545
return mkApp (← mkLeLtPrefix declName) s.isLinearPreInst?.get!
4646

47+
/--
48+
Returns `declName α leInst isLinearPreorderInst`
49+
-/
50+
public def mkLeLinearPrefix (declName : Name) : OrderM Expr := do
51+
let s ← getStruct
52+
return mkApp3 (mkConst declName [s.u]) s.type s.leInst s.isLinearPreInst?.get!
53+
4754
/--
4855
Returns `declName α leInst ltInst lawfulOrderLtInst isPreorderInst ringInst ordRingInst`
4956
-/
@@ -52,6 +59,14 @@ def mkOrdRingPrefix (declName : Name) : OrderM Expr := do
5259
let h ← mkLeLtPreorderPrefix declName
5360
return mkApp2 h s.ringInst?.get! s.orderedRingInst?.get!
5461

62+
/--
63+
Returns `declName α leInst ltInst lawfulOrderLtInst isLinearPreorderInst ringInst ordRingInst`
64+
-/
65+
public def mkLinearOrdRingPrefix (declName : Name) : OrderM Expr := do
66+
let s ← getStruct
67+
let h ← mkLeLtLinearPrefix declName
68+
return mkApp2 h s.ringInst?.get! s.orderedRingInst?.get!
69+
5570
def mkTransCoreProof (u v w : Expr) (strict₁ strict₂ : Bool) (h₁ h₂ : Expr) : OrderM Expr := do
5671
let h ← match strict₁, strict₂ with
5772
| false, false => mkLePreorderPrefix ``Grind.Order.le_trans

tests/lean/run/grind_offset_cnstr.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module
22
set_option grind.debug true
3-
3+
set_option warn.sorry false
44
/--
55
trace: [grind.offset.internalize.term] a1 ↦ #0
66
[grind.offset.internalize.term] a2 ↦ #1
@@ -274,7 +274,7 @@ trace: [grind.debug.proof] intro_with_eq (p ↔ a2 ≤ a1) (p = (a2 ≤ a1)) (¬
274274
open Lean Grind in
275275
set_option trace.grind.debug.proof true in
276276
theorem ex1 (p : Prop) (a1 a2 a3 : Nat) : (p ↔ a2 ≤ a1) → ¬p → a2 + 3 ≤ a3 → (p ↔ a4 ≤ a3 + 2) → a1 ≤ a4 := by
277-
grind
277+
grind -order
278278

279279
/-! Propagate `cnstr = False` tests -/
280280

tests/lean/run/grind_order_3.lean

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
open Lean Grind
2+
3+
example [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsLinearPreorder α]
4+
(a b c d : α) : a ≤ b → ¬ (c ≤ b) → ¬ (d ≤ c) → d < a → False := by
5+
grind -linarith (splits := 0)
6+
7+
example [LE α] [Std.IsLinearPreorder α]
8+
(a b c d : α) : a ≤ b → ¬ (c ≤ b) → ¬ (d ≤ c) → ¬ (a ≤ d) → False := by
9+
grind -linarith (splits := 0)
10+
11+
example [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsLinearPreorder α] [CommRing α] [OrderedRing α]
12+
(a b c d : α) : a - b ≤ 5 → ¬ (c ≤ b) → ¬ (d ≤ c + 2) → d ≤ a - 8 → False := by
13+
grind -linarith (splits := 0)
14+
15+
example [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsLinearPreorder α] [CommRing α] [OrderedRing α]
16+
(a b c d : α) : a - b ≤ 5 → ¬ (c < b) → ¬ (d ≤ c + 2) → d ≤ a - 8 → False := by
17+
grind -linarith (splits := 0)
18+
19+
example (p : Prop) (a b c : Int) : (p ↔ b ≤ a) → (p ↔ c ≤ b) → ¬ p → c ≤ a + 1 → False := by
20+
grind -linarith -cutsat (splits := 0)

0 commit comments

Comments
 (0)