Skip to content

Commit 744f04f

Browse files
committed
feat: proofs for theory propagation in grind order
This PR implements proof construction for theory propagation in `grind order`.
1 parent 69c8f13 commit 744f04f

File tree

3 files changed

+128
-22
lines changed

3 files changed

+128
-22
lines changed

src/Init/Grind/Order.lean

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ private theorem add_lt_add_of_lt_of_le {α} [LE α] [LT α] [Std.LawfulOrderLT
143143

144144
/-! Theorems for propagating constraints to `True` -/
145145

146+
theorem le_eq_true_of_lt {α} [LE α] [LT α] [Std.LawfulOrderLT α]
147+
(a b : α) : a < b → (a ≤ b) = True := by
148+
simp; intro h
149+
exact Std.le_of_lt h
150+
146151
theorem le_eq_true_of_le_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
147152
(a b : α) (k₁ k₂ : Int) : k₁.ble' k₂ → a ≤ b + k₁ → (a ≤ b + k₂) = True := by
148153
simp; intro h₁ h₂
@@ -184,6 +189,13 @@ theorem lt_eq_true_of_le_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPr
184189

185190
/-! Theorems for propagating constraints to `False` -/
186191

192+
theorem le_eq_false_of_lt {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α]
193+
(a b : α) : a < b → (b ≤ a) = False := by
194+
simp; intro h₁ h₂
195+
have := lt_le_trans h₁ h₂
196+
have := Preorder.lt_irrefl a
197+
contradiction
198+
187199
theorem le_eq_false_of_le_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
188200
(a b : α) (k₁ k₂ : Int) : (k₂ + k₁).blt' 0 → a ≤ b + k₁ → (b ≤ a + k₂) = False := by
189201
intro h₁; simp; intro h₂ h₃

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,7 @@ def getProof (u v : NodeId) : OrderM ProofInfo := do
5454
def getCnstr? (e : Expr) : OrderM (Option (Cnstr NodeId)) :=
5555
return (← getStruct).cnstrs.find? { expr := e }
5656

57+
def isRing : OrderM Bool :=
58+
return (← getStruct).ringId?.isSome
59+
5760
end Lean.Meta.Grind.Order

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

Lines changed: 113 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,35 @@ def mkLePreorderPrefix (declName : Name) : OrderM Expr := do
1717
return mkApp3 (mkConst declName [s.u]) s.type s.leInst s.isPreorderInst
1818

1919
/--
20-
Returns `declName α leInst ltInst lawfulOrderLtInst isPreorderInst`
20+
Returns `declName α leInst ltInst lawfulOrderLtInst`
2121
-/
2222
def mkLeLtPrefix (declName : Name) : OrderM Expr := do
2323
let s ← getStruct
24-
return mkApp5 (mkConst declName [s.u]) s.type s.leInst s.ltInst?.get! s.lawfulOrderLTInst?.get! s.isPreorderInst
24+
return mkApp4 (mkConst declName [s.u]) s.type s.leInst s.ltInst?.get! s.lawfulOrderLTInst?.get!
25+
26+
/--
27+
Returns `declName α leInst ltInst lawfulOrderLtInst isPreorderInst`
28+
-/
29+
def mkLeLtPreorderPrefix (declName : Name) : OrderM Expr := do
30+
let s ← getStruct
31+
return mkApp (← mkLeLtPrefix declName) s.isPreorderInst
2532

2633
/--
2734
Returns `declName α leInst ltInst lawfulOrderLtInst isPreorderInst ringInst ordRingInst`
2835
-/
2936
def mkOrdRingPrefix (declName : Name) : OrderM Expr := do
3037
let s ← getStruct
31-
let h ← mkLeLtPrefix declName
38+
let h ← mkLeLtPreorderPrefix declName
3239
return mkApp2 h s.ringInst?.get! s.orderedRingInst?.get!
3340

41+
def mkTransCoreProof (u v w : Expr) (strict₁ strict₂ : Bool) (h₁ h₂ : Expr) : OrderM Expr := do
42+
let h ← match strict₁, strict₂ with
43+
| false, false => mkLePreorderPrefix ``Grind.Order.le_trans
44+
| false, true => mkLeLtPreorderPrefix ``Grind.Order.le_lt_trans
45+
| true, false => mkLeLtPreorderPrefix ``Grind.Order.lt_le_trans
46+
| true, true => mkLeLtPreorderPrefix ``Grind.Order.lt_trans
47+
return mkApp5 h u v w h₁ h₂
48+
3449
/--
3550
Assume `p₁` is `{ w := u, k := k₁, proof := p₁ }` and `p₂` is `{ w := w, k := k₂, proof := p₂ }`
3651
`p₁` is the proof for edge `u → w` and `p₂` the proof for edge `w -> v`.
@@ -41,15 +56,20 @@ Remark: for orders that do not support offsets.
4156
def mkTransCore (p₁ : ProofInfo) (p₂ : ProofInfo) (v : NodeId) : OrderM ProofInfo := do
4257
let { w := u, k.strict := s₁, proof := h₁, .. } := p₁
4358
let { w, k.strict := s₂, proof := h₂, .. } := p₂
44-
let h ← match s₁, s₂ with
45-
| false, false => mkLePreorderPrefix ``Grind.Order.le_trans
46-
| false, true => mkLeLtPrefix ``Grind.Order.le_lt_trans
47-
| true, false => mkLeLtPrefix ``Grind.Order.lt_le_trans
48-
| true, true => mkLeLtPrefix ``Grind.Order.lt_trans
4959
let ns := (← getStruct).nodes
50-
let h := mkApp5 h ns[u]! ns[w]! ns[v]! h₁ h₂
60+
let h ← mkTransCoreProof ns[u]! ns[w]! ns[v]! s₁ s₂ h₁ h₂
5161
return { w := p₁.w, k.strict := s₁ || s₂, proof := h }
5262

63+
def mkTransOffsetProof (u v w : Expr) (k₁ k₂ : Weight) (h₁ h₂ : Expr) : OrderM Expr := do
64+
let h ← match k₁.strict, k₂.strict with
65+
| false, false => mkOrdRingPrefix ``Grind.Order.le_trans_k
66+
| false, true => mkOrdRingPrefix ``Grind.Order.le_lt_trans_k
67+
| true, false => mkOrdRingPrefix ``Grind.Order.lt_le_trans_k
68+
| true, true => mkOrdRingPrefix ``Grind.Order.lt_trans_k
69+
let k := k₁.k + k₂.k
70+
let h := mkApp6 h u v w (toExpr k₁.k) (toExpr k₂.k) (toExpr k)
71+
return mkApp3 h h₁ h₂ eagerReflBoolTrue
72+
5373
/--
5474
Assume `p₁` is `{ w := u, k := k₁, proof := p₁ }` and `p₂` is `{ w := w, k := k₂, proof := p₂ }`
5575
`p₁` is the proof for edge `u -(k₁)→ w` and `p₂` the proof for edge `w -(k₂)-> v`.
@@ -58,18 +78,11 @@ Then, this function returns a proof for edge `u -(k₁+k₂) -> v`.
5878
Remark: for orders that support offsets.
5979
-/
6080
def mkTransOffset (p₁ : ProofInfo) (p₂ : ProofInfo) (v : NodeId) : OrderM ProofInfo := do
61-
let { w := u, k.k := k₁, k.strict := s₁, proof := h₁, .. } := p₁
62-
let { w, k.k := k₂, k.strict := s₂, proof := h₂, .. } := p₂
63-
let h ← match s₁, s₂ with
64-
| false, false => mkOrdRingPrefix ``Grind.Order.le_trans_k
65-
| false, true => mkOrdRingPrefix ``Grind.Order.le_lt_trans_k
66-
| true, false => mkOrdRingPrefix ``Grind.Order.lt_le_trans_k
67-
| true, true => mkOrdRingPrefix ``Grind.Order.lt_trans_k
68-
let k := k₁ + k₂
81+
let { w := u, k:= k₁, proof := h₁, .. } := p₁
82+
let { w, k := k₂, proof := h₂, .. } := p₂
6983
let ns := (← getStruct).nodes
70-
let h := mkApp6 h ns[u]! ns[w]! ns[v]! (toExpr k₁) (toExpr k₂) (toExpr k)
71-
let h := mkApp3 h h₁ h₂ eagerReflBoolTrue
72-
return { w := p₁.w, k.k := k, k.strict := s₁ || s₂, proof := h }
84+
let h ← mkTransOffsetProof ns[u]! ns[w]! ns[v]! k₁ k₂ h₁ h₂
85+
return { w := p₁.w, k.k := k₁.k + k₂.k, k.strict := k₁.strict || k₂.strict, proof := h }
7386

7487
/--
7588
Assume `p₁` is `{ w := u, k := k₁, proof := p₁ }` and `p₂` is `{ w := w, k := k₂, proof := p₂ }`
@@ -79,10 +92,88 @@ Then, this function returns a proof for edge `u -(k₁+k₂) -> v`.
7992
Remark: if the order does not support offset `k₁` and `k₂` are zero.
8093
-/
8194
public def mkTrans (p₁ : ProofInfo) (p₂ : ProofInfo) (v : NodeId) : OrderM ProofInfo := do
82-
let s ← getStruct
83-
if s.orderedRingInst?.isSome then
95+
if (← isRing) then
8496
mkTransOffset p₁ p₂ v
8597
else
8698
mkTransCore p₁ p₂ v
8799

100+
def mkPropagateEqTrueProofCore (u v : Expr) (k : Weight) (huv : Expr) (k' : Weight) : OrderM Expr := do
101+
if k.strict == k'.strict then
102+
mkEqTrue huv
103+
else
104+
assert! k.strict && !k'.strict
105+
let h ← mkLeLtPrefix ``Grind.Order.le_eq_true_of_lt
106+
return mkApp3 h u v huv
107+
108+
def mkPropagateEqTrueProofOffset (u v : Expr) (k : Weight) (huv : Expr) (k' : Weight) : OrderM Expr := do
109+
let declName := match k'.strict, k.strict with
110+
| false, false => ``Grind.Order.le_eq_true_of_le_k
111+
| false, true => ``Grind.Order.le_eq_true_of_lt_k
112+
| true, false => ``Grind.Order.lt_eq_true_of_le_k
113+
| true, true => ``Grind.Order.lt_eq_true_of_lt_k
114+
let h ← mkOrdRingPrefix declName
115+
return mkApp6 h u v (toExpr k.k) (toExpr k'.k) eagerReflBoolTrue huv
116+
117+
/--
118+
Given a path `u --(k)--> v` justified by proof `huv`,
119+
construct a proof of `e = True` where `e` is a term corresponding to the edge `u --(k') --> v`
120+
-/
121+
public def mkPropagateEqTrueProof (u v : Expr) (k : Weight) (huv : Expr) (k' : Weight) : OrderM Expr := do
122+
if (← isRing) then
123+
mkPropagateEqTrueProofOffset u v k huv k'
124+
else
125+
mkPropagateEqTrueProofCore u v k huv k'
126+
127+
/--
128+
`u < v → (v ≤ u) = False
129+
-/
130+
def mkPropagateEqFalseProofCore (u v : Expr) (huv : Expr) : OrderM Expr := do
131+
let h ← mkLeLtPreorderPrefix ``Grind.Order.le_eq_false_of_lt
132+
return mkApp3 h u v huv
133+
134+
def mkPropagateEqFalseProofOffset (u v : Expr) (k : Weight) (huv : Expr) (k' : Weight) : OrderM Expr := do
135+
let declName := match k'.strict, k.strict with
136+
| false, false => ``Grind.Order.le_eq_false_of_le_k
137+
| false, true => ``Grind.Order.le_eq_false_of_lt_k
138+
| true, false => ``Grind.Order.lt_eq_false_of_le_k
139+
| true, true => ``Grind.Order.lt_eq_false_of_lt_k
140+
let h ← mkOrdRingPrefix declName
141+
return mkApp6 h u v (toExpr k.k) (toExpr k'.k) eagerReflBoolTrue huv
142+
143+
/--
144+
Given a path `u --(k)--> v` justified by proof `huv`,
145+
construct a proof of `e = False` where `e` is a term corresponding to the edge `u --(k') --> v`
146+
-/
147+
public def mkPropagateEqFalseProof (u v : Expr) (k : Weight) (huv : Expr) (k' : Weight) : OrderM Expr := do
148+
if (← isRing) then
149+
mkPropagateEqFalseProofOffset u v k huv k'
150+
else
151+
mkPropagateEqFalseProofCore u v huv
152+
153+
def mkUnsatProofCore (u v : Expr) (k₁ : Weight) (h₁ : Expr) (k₂ : Weight) (h₂ : Expr) : OrderM Expr := do
154+
let h ← mkTransCoreProof u v u k₁.strict k₂.strict h₁ h₂
155+
assert! k₁.strict || k₂.strict
156+
let hf ← mkLeLtPreorderPrefix ``Grind.Order.lt_unsat
157+
return mkApp2 hf u h
158+
159+
def mkUnsatProofOffset (u v : Expr) (k₁ : Weight) (h₁ : Expr) (k₂ : Weight) (h₂ : Expr) : OrderM Expr := do
160+
let h ← mkTransOffsetProof u v u k₁ k₂ h₁ h₂
161+
let declName := if k₁.strict || k₂.strict then
162+
``Grind.Order.lt_unsat_k
163+
else
164+
``Grind.Order.le_unsat_k
165+
let hf ← mkOrdRingPrefix declName
166+
return mkApp4 hf u (toExpr (k₁.k + k₂.k)) eagerReflBoolTrue h
167+
168+
/--
169+
Returns a proof of `False` using a negative cycle composed of
170+
- `u --(k₁)--> v` with proof `h₁`
171+
- `v --(k₂)--> u` with proof `h₂`
172+
-/
173+
def mkUnsatProof (u v : Expr) (k₁ : Weight) (h₁ : Expr) (k₂ : Weight) (h₂ : Expr) : OrderM Expr := do
174+
if (← isRing) then
175+
mkUnsatProofOffset u v k₁ h₁ k₂ h₂
176+
else
177+
mkUnsatProofCore u v k₁ h₁ k₂ h₂
178+
88179
end Lean.Meta.Grind.Order

0 commit comments

Comments
 (0)