Compare commits

...

7 Commits

Author SHA1 Message Date
Leonardo de Moura
e746613ecc chore: fix test 2025-08-12 12:10:17 -07:00
Leonardo de Moura
a2d41bf1f8 Update src/Init/Core.lean
Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
2025-08-12 11:36:05 -07:00
Leonardo de Moura
2fd1f2b588 chore: fix test 2025-08-12 11:00:52 -07:00
Leonardo de Moura
f644affd8f feat: replace hint in the kernel 2025-08-12 11:00:52 -07:00
Leonardo de Moura
8ed9e3b0c0 chore: use eagerReduce in our proofs by reflection 2025-08-12 11:00:52 -07:00
Leonardo de Moura
a50abdcf88 chore: eagerReduce 2025-08-12 11:00:52 -07:00
Leonardo de Moura
7caad98589 feat: kernel hint for proof-by-reflection
This PR adds improved support for proof-by-reflection to the kernel
type checker. It addresses the performance issue exposed by #9854.
With this PR, whenever the kernel type-checks an argument of the form
`Eq.refl true`, it enters "proof-by-reflection" mode. In this mode,
the kernel is more eager to reduce terms. If the PR negatively
impacts existing packages, we can use a different a new `Eq.refl`
theorem as the "hint."
2025-08-12 11:00:52 -07:00
21 changed files with 194 additions and 143 deletions

View File

@@ -29,6 +29,29 @@ theorem id_def {α : Sort u} (a : α) : id a = a := rfl
attribute [grind] id
/--
A helper gadget for instructing the kernel to eagerly reduce terms.
When the gadget wraps the argument of an application, then when checking that
the expected and inferred type of the argument match, the kernel will evaluate terms more eagerly.
It is often used to wrap `Eq.refl true` proof terms as `eagerReduce (Eq.refl true)`
when using proof by reflection.
As an example, consider the theorem:
```
theorem eq_norm (ctx : Context) (p₁ p₂ : Poly) (h : (p₁.norm == p₂) = true) :
p₁.denote ctx = 0 → p₂.denote ctx = 0
```
The argument `h : (p₁.norm == p₂) = true` is a candidate for `eagerReduce`.
When applying this theorem, we would write:
```
eq_norm ctx p q (eagerReduce (Eq.refl true)) h
```
to instruct the kernel to use eager reduction when establishing that `(p.norm == q) = true` is
definitionally equal to `true = true`.
-/
@[expose] def eagerReduce {α : Sort u} (a : α) : α := a
/--
`flip f a b` is `f b a`. It is useful for "point-free" programming,
since it can sometimes be used to avoid introducing variables.

View File

@@ -2384,4 +2384,10 @@ def reflBoolTrue : Expr :=
def reflBoolFalse : Expr :=
mkApp2 (mkConst ``Eq.refl [levelOne]) (mkConst ``Bool) (mkConst ``Bool.false)
def eagerReflBoolTrue : Expr :=
mkApp2 (mkConst ``eagerReduce [0]) (mkApp3 (mkConst ``Eq [1]) (mkConst ``Bool) (mkConst ``Bool.true) (mkConst ``Bool.true)) reflBoolTrue
def eagerReflBoolFalse : Expr :=
mkApp2 (mkConst ``eagerReduce [0]) (mkApp3 (mkConst ``Eq [1]) (mkConst ``Bool) (mkConst ``Bool.false) (mkConst ``Bool.false)) reflBoolFalse
end Lean

View File

@@ -177,7 +177,7 @@ def litToCtor (e : Expr) : MetaM Expr := do
let p := mkApp4 (mkConst ``LT.lt [0]) (mkConst ``Nat) (mkConst ``instLTNat) i n
let h := mkApp3 (mkConst ``of_decide_eq_true) p
(mkApp2 (mkConst ``Nat.decLt) i n)
reflBoolTrue
eagerReflBoolTrue
return mkApp3 (mkConst ``Fin.mk) n i h
return e

View File

@@ -86,17 +86,17 @@ private def processInv (e inst a : Expr) : RingM Unit := do
if c == 0 then
let expected mkEq (mkApp2 ( getMulFn) a e) ( denoteNum 1)
pushNewFact <| mkExpectedPropHint
(mkApp5 (mkConst ``Grind.CommRing.inv_int_eq [ring.u]) ring.type fieldInst charInst (mkIntLit k) reflBoolTrue)
(mkApp5 (mkConst ``Grind.CommRing.inv_int_eq [ring.u]) ring.type fieldInst charInst (mkIntLit k) eagerReflBoolTrue)
expected
else if k % c == 0 then
let expected mkEq e ( denoteNum 0)
pushNewFact <| mkExpectedPropHint
(mkApp6 (mkConst ``Grind.CommRing.inv_zero_eqC [ring.u]) ring.type (mkNatLit c) fieldInst charInst (mkIntLit k) reflBoolTrue)
(mkApp6 (mkConst ``Grind.CommRing.inv_zero_eqC [ring.u]) ring.type (mkNatLit c) fieldInst charInst (mkIntLit k) eagerReflBoolTrue)
expected
else
let expected mkEq (mkApp2 ( getMulFn) a e) ( denoteNum 1)
pushNewFact <| mkExpectedPropHint
(mkApp6 (mkConst ``Grind.CommRing.inv_int_eqC [ring.u]) ring.type (mkNatLit c) fieldInst charInst (mkIntLit k) reflBoolTrue)
(mkApp6 (mkConst ``Grind.CommRing.inv_int_eqC [ring.u]) ring.type (mkNatLit c) fieldInst charInst (mkIntLit k) eagerReflBoolTrue)
expected
return ()
pushNewFact <| mkApp3 (mkConst ``Grind.CommRing.inv_split [ring.u]) ring.type fieldInst a

View File

@@ -267,7 +267,7 @@ def setEqUnsat (c : EqCnstr) : RingM Unit := do
mkApp2 (mkConst ``Grind.CommRing.NullCert.eq_unsatC [ring.u]) ring.type (toExpr char)
let ctx toContextExpr
let nc := toExpr (ncx.toNullCert)
let h := mkApp6 h ring.commRingInst charInst ctx nc (toExpr k) reflBoolTrue
let h := mkApp6 h ring.commRingInst charInst ctx nc (toExpr k) eagerReflBoolTrue
closeGoal <| ncx.applyEqs h
def setDiseqUnsat (c : DiseqCnstr) : RingM Unit := do
@@ -287,7 +287,7 @@ def setDiseqUnsat (c : DiseqCnstr) : RingM Unit := do
mkApp6 (mkConst ``Grind.CommRing.NullCert.ne_nzdiv_unsat [ring.u]) ring.type ring.commRingInst nzDivInst ctx nc (toExpr k)
| none, none =>
mkApp4 (mkConst ``Grind.CommRing.NullCert.ne_unsat [ring.u]) ring.type ring.commRingInst ctx nc
let h := mkApp4 h (toExpr c.rlhs) (toExpr c.rrhs) reflBoolTrue ( mkDiseqProof c.lhs c.rhs)
let h := mkApp4 h (toExpr c.rlhs) (toExpr c.rrhs) eagerReflBoolTrue ( mkDiseqProof c.lhs c.rhs)
closeGoal <| ncx.applyEqs h
def propagateEq (a b : Expr) (ra rb : RingExpr) (d : PolyDerivation) : RingM Unit := do
@@ -305,7 +305,7 @@ def propagateEq (a b : Expr) (ra rb : RingExpr) (d : PolyDerivation) : RingM Uni
mkApp6 (mkConst ``Grind.CommRing.NullCert.eq_nzdiv [ring.u]) ring.type ring.commRingInst nzDivInst ctx nc (toExpr k)
| none, none =>
mkApp4 (mkConst ``Grind.CommRing.NullCert.eq [ring.u]) ring.type ring.commRingInst ctx nc
let h := mkApp3 h (toExpr ra) (toExpr rb) reflBoolTrue
let h := mkApp3 h (toExpr ra) (toExpr rb) eagerReflBoolTrue
trace_goal[grind.debug.ring.impEq] "{a}, {b}"
let eq := mkApp3 (mkConst ``Eq [.succ ring.u]) ring.type a b
pushEq a b <| mkExpectedPropHint (ncx.applyEqs h) eq
@@ -419,40 +419,40 @@ partial def _root_.Lean.Meta.Grind.Arith.CommRing.EqCnstr.toExprProof (c : EqCns
match c.h with
| .core a b lhs rhs =>
let h mkStepPrefix ``Stepwise.core ``Stepwise.coreC
return mkApp5 h ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c.p) reflBoolTrue ( mkEqProof a b)
return mkApp5 h ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c.p) eagerReflBoolTrue ( mkEqProof a b)
| .coreS a b sa sb ra rb =>
let h' mkSemiringPrefix ``Grind.Ring.OfSemiring.of_eq
let h' := mkApp3 h' ( mkSExprDecl sa) ( mkSExprDecl sb) ( mkEqProof a b)
let h mkStepPrefix ``Stepwise.core ``Stepwise.coreC
return mkApp5 h ( mkExprDecl ra) ( mkExprDecl rb) ( mkPolyDecl c.p) reflBoolTrue h'
return mkApp5 h ( mkExprDecl ra) ( mkExprDecl rb) ( mkPolyDecl c.p) eagerReflBoolTrue h'
| .superpose k₁ m₁ c₁ k₂ m₂ c₂ =>
let h mkStepPrefix ``Stepwise.superpose ``Stepwise.superposeC
return mkApp10 h
(toExpr k₁) ( mkMonDecl m₁) ( mkPolyDecl c₁.p)
(toExpr k₂) ( mkMonDecl m₂) ( mkPolyDecl c₂.p)
( mkPolyDecl c.p) reflBoolTrue ( toExprProof c₁) ( toExprProof c₂)
( mkPolyDecl c.p) eagerReflBoolTrue ( toExprProof c₁) ( toExprProof c₂)
| .simp k₁ c₁ k₂ m₂ c₂ =>
let h mkStepPrefix ``Stepwise.simp ``Stepwise.simpC
return mkApp9 h
(toExpr k₁) ( mkPolyDecl c₁.p)
(toExpr k₂) ( mkMonDecl m₂) ( mkPolyDecl c₂.p)
( mkPolyDecl c.p) reflBoolTrue ( toExprProof c₁) ( toExprProof c₂)
( mkPolyDecl c.p) eagerReflBoolTrue ( toExprProof c₁) ( toExprProof c₂)
| .mul k c₁ =>
let h mkStepPrefix ``Stepwise.mul ``Stepwise.mulC
return mkApp5 h ( mkPolyDecl c₁.p) (toExpr k) ( mkPolyDecl c.p) reflBoolTrue ( toExprProof c₁)
return mkApp5 h ( mkPolyDecl c₁.p) (toExpr k) ( mkPolyDecl c.p) eagerReflBoolTrue ( toExprProof c₁)
| .div k c₁ =>
let h mkStepPrefix ``Stepwise.div ``Stepwise.divC
let some nzInst noZeroDivisorsInst?
| throwNoNatZeroDivisors
return mkApp6 h nzInst ( mkPolyDecl c₁.p) (toExpr k) ( mkPolyDecl c.p) reflBoolTrue ( toExprProof c₁)
return mkApp6 h nzInst ( mkPolyDecl c₁.p) (toExpr k) ( mkPolyDecl c.p) eagerReflBoolTrue ( toExprProof c₁)
| .gcd a b c₁ c₂ =>
let h mkStepBasicPrefix ``Grind.CommRing.eq_gcd
return mkApp8 h (toExpr a) (toExpr b) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c.p)
reflBoolTrue ( toExprProof c₁) ( toExprProof c₂)
eagerReflBoolTrue ( toExprProof c₁) ( toExprProof c₂)
| .numEq0 k c₁ c₂ =>
let h mkStepBasicPrefix ``Grind.CommRing.eq_normEq0
return mkApp7 h (toExpr k) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c.p)
reflBoolTrue ( toExprProof c₁) ( toExprProof c₂)
eagerReflBoolTrue ( toExprProof c₁) ( toExprProof c₂)
open Lean.Grind.CommRing in
/--
@@ -474,7 +474,7 @@ private def derivToExprProof (d : PolyDerivation) : ProofM (Int × Poly × Expr)
let h := mkApp10 h
(toExpr k) ( mkPolyDecl p₀) ( mkPolyDecl d.p)
(toExpr k₂) ( mkMonDecl m₂) ( mkPolyDecl c₂.p) ( mkPolyDecl p)
reflBoolTrue h₁ h₂
eagerReflBoolTrue h₁ h₂
return (k₁*k, p₀, h)
| .normEq0 p d c =>
let (k, p₀, h₁) derivToExprProof d
@@ -483,7 +483,7 @@ private def derivToExprProof (d : PolyDerivation) : ProofM (Int × Poly × Expr)
let h mkStepBasicPrefix ``Grind.CommRing.d_normEq0
let h := mkApp9 h
(toExpr k) (toExpr a.natAbs) ( mkPolyDecl p₀) ( mkPolyDecl d.p)
( mkPolyDecl c.p) ( mkPolyDecl p) reflBoolTrue h₁ h₂
( mkPolyDecl c.p) ( mkPolyDecl p) eagerReflBoolTrue h₁ h₂
return (k, p₀, h)
open Lean.Grind.CommRing in
@@ -499,7 +499,7 @@ private def mkImpEqExprProof (lhs rhs : RingExpr) (d : PolyDerivation) : ProofM
let some nzInst noZeroDivisorsInst?
| throwNoNatZeroDivisors
pure <| mkApp2 ( mkStepPrefix ``Stepwise.imp_keq ``Stepwise.imp_keqC) nzInst (toExpr k)
return mkApp6 h ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl p₀) ( mkPolyDecl d.p) reflBoolTrue h₁
return mkApp6 h ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl p₀) ( mkPolyDecl d.p) eagerReflBoolTrue h₁
private abbrev withSemiringContext (k : Option Expr RingM Expr) : RingM Expr := do
let some semiringId := ( getRing).semiringId? | k none
@@ -532,10 +532,10 @@ def setEqUnsat (c : EqCnstr) : RingM Unit := do
if char == 0 then
h := mkApp h charInst
let k getPolyConst c.p
return mkApp4 h ( mkPolyDecl c.p) (toExpr k) reflBoolTrue ( c.toExprProof)
return mkApp4 h ( mkPolyDecl c.p) (toExpr k) eagerReflBoolTrue ( c.toExprProof)
else if let some fieldInst := ring.fieldInst? then
return mkApp6 (mkConst ``Grind.CommRing.one_eq_zero_unsat [ring.u]) ring.type fieldInst ( getContext)
( mkPolyDecl c.p) reflBoolTrue ( c.toExprProof)
( mkPolyDecl c.p) eagerReflBoolTrue ( c.toExprProof)
else
throwError "`grind ring` internal error, unexpected unsat eq proof {← c.denoteExpr}"
closeGoal h
@@ -587,7 +587,7 @@ def setSemiringDiseqUnsat (a b : Expr) (sa sb : SemiringExpr) : SemiringM Unit :
let semiring getSemiring
let hne mkDiseqProof a b
let h := mkApp3 (mkConst ``Grind.Ring.OfSemiring.eq_normS [semiring.u]) semiring.type semiring.commSemiringInst ctx
let h := mkApp3 h (toExpr sa) (toExpr sb) reflBoolTrue
let h := mkApp3 h (toExpr sa) (toExpr sb) eagerReflBoolTrue
closeGoal (mkApp hne h)
end Lean.Meta.Grind.Arith.CommRing

View File

@@ -107,7 +107,7 @@ def propagateIntDvd (e : Expr) : GoalM Unit := do
let c := { d, p, h := .core e : DvdCnstr }
c.assertCore
else if ( isEqFalse e) then
pushNewFact <| mkApp4 (mkConst ``Int.Linear.of_not_dvd) a b reflBoolTrue (mkOfEqFalseCore e ( mkEqFalseProof e))
pushNewFact <| mkApp4 (mkConst ``Int.Linear.of_not_dvd) a b eagerReflBoolTrue (mkOfEqFalseCore e ( mkEqFalseProof e))
def propagateNatDvd (e : Expr) : GoalM Unit := do
let_expr Dvd.dvd _ inst d₀ a := e | return ()

View File

@@ -403,8 +403,8 @@ private def expandDivMod (a : Expr) (b : Int) : GoalM Unit := do
let n : Int := 1 - b.natAbs
let b := mkIntLit b
pushNewFact <| mkApp2 (mkConst ``Int.Linear.ediv_emod) a b
pushNewFact <| mkApp3 (mkConst ``Int.Linear.emod_nonneg) a b reflBoolTrue
pushNewFact <| mkApp4 (mkConst ``Int.Linear.emod_le) a b (toExpr n) reflBoolTrue
pushNewFact <| mkApp3 (mkConst ``Int.Linear.emod_nonneg) a b eagerReflBoolTrue
pushNewFact <| mkApp4 (mkConst ``Int.Linear.emod_le) a b (toExpr n) eagerReflBoolTrue
private def propagateDiv (e : Expr) : GoalM Unit := do
let_expr HDiv.hDiv _ _ _ inst a b e | return ()

View File

@@ -156,7 +156,7 @@ partial def mkNonnegThm? (e : Expr) : GoalM (Option Expr) := do
where
go (e : Expr) : MetaM Expr := do
match_expr e with
| OfNat.ofNat _ _ _ => return mkApp2 (mkConst ``Int.Nonneg.num) e reflBoolTrue
| OfNat.ofNat _ _ _ => return mkApp2 (mkConst ``Int.Nonneg.num) e eagerReflBoolTrue
| HAdd.hAdd _ _ _ _ a b => return mkApp4 (mkConst ``Int.Nonneg.add) a b ( go a) ( go b)
| HMul.hMul _ _ _ _ a b => return mkApp4 (mkConst ``Int.Nonneg.mul) a b ( go a) ( go b)
| HDiv.hDiv _ _ _ _ a b => return mkApp4 (mkConst ``Int.Nonneg.div) a b ( go a) ( go b)

View File

@@ -149,44 +149,44 @@ partial def EqCnstr.toExprProof (c' : EqCnstr) : ProofM Expr := caching c' do
mkEqProof a zero
| .core a b p₁ p₂ =>
let h mkEqProof a b
return mkApp6 (mkConst ``Int.Linear.eq_of_core) ( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂) ( mkPolyDecl c'.p) reflBoolTrue h
return mkApp6 (mkConst ``Int.Linear.eq_of_core) ( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂) ( mkPolyDecl c'.p) eagerReflBoolTrue h
| .coreToInt a b toIntThm lhs rhs =>
let h := mkApp toIntThm ( mkEqProof a b)
return mkApp6 (mkConst ``Int.Linear.eq_norm_expr) ( getContext) ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c'.p) reflBoolTrue h
return mkApp6 (mkConst ``Int.Linear.eq_norm_expr) ( getContext) ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c'.p) eagerReflBoolTrue h
| .defn e p =>
let some x := ( getVarMap).find? { expr := e } | throwError "`grind` internal error, missing cutsat variable{indentExpr e}"
return mkApp6 (mkConst ``Int.Linear.eq_def) ( getContext) (toExpr x) ( mkPolyDecl p) ( mkPolyDecl c'.p) reflBoolTrue ( mkEqRefl e)
return mkApp6 (mkConst ``Int.Linear.eq_def) ( getContext) (toExpr x) ( mkPolyDecl p) ( mkPolyDecl c'.p) eagerReflBoolTrue ( mkEqRefl e)
| .defnNat h x e =>
return mkApp6 (mkConst ``Int.Linear.eq_def') ( getContext) (toExpr x) ( mkExprDecl e) ( mkPolyDecl c'.p) reflBoolTrue h
return mkApp6 (mkConst ``Int.Linear.eq_def') ( getContext) (toExpr x) ( mkExprDecl e) ( mkPolyDecl c'.p) eagerReflBoolTrue h
| .norm c =>
return mkApp5 (mkConst ``Int.Linear.eq_norm) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) reflBoolTrue ( c.toExprProof)
return mkApp5 (mkConst ``Int.Linear.eq_norm) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) eagerReflBoolTrue ( c.toExprProof)
| .divCoeffs c =>
let k := c.p.gcdCoeffs c.p.getConst
return mkApp6 (mkConst ``Int.Linear.eq_coeff) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) (toExpr k) reflBoolTrue ( c.toExprProof)
return mkApp6 (mkConst ``Int.Linear.eq_coeff) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) (toExpr k) eagerReflBoolTrue ( c.toExprProof)
| .subst x c₁ c₂ =>
let a := c₁.p.coeff x
let b := c₂.p.coeff x
return mkApp9 (mkConst ``Int.Linear.eq_eq_subst')
( getContext) (toExpr a) (toExpr b) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c'.p)
reflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
eagerReflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
| .ofLeGe c₁ c₂ =>
return mkApp6 (mkConst ``Int.Linear.eq_of_le_ge)
( getContext) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p)
reflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
eagerReflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
| .reorder c => withUnordered <| c.toExprProof
| .commRingNorm c e p =>
let h := mkApp4 (mkConst ``Grind.CommRing.norm_int) ( getRingContext) ( mkRingExprDecl e) ( mkRingPolyDecl p) reflBoolTrue
let h := mkApp4 (mkConst ``Grind.CommRing.norm_int) ( getRingContext) ( mkRingExprDecl e) ( mkRingPolyDecl p) eagerReflBoolTrue
return mkApp5 (mkConst ``Int.Linear.eq_norm_poly) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) h ( c.toExprProof)
| .defnCommRing e p re rp p' =>
let h := mkApp4 (mkConst ``Grind.CommRing.norm_int) ( getRingContext) ( mkRingExprDecl re) ( mkRingPolyDecl rp) reflBoolTrue
let h := mkApp4 (mkConst ``Grind.CommRing.norm_int) ( getRingContext) ( mkRingExprDecl re) ( mkRingPolyDecl rp) eagerReflBoolTrue
let some x := ( getVarMap).find? { expr := e } | throwError "`grind` internal error, missing cutsat variable{indentExpr e}"
return mkApp8 (mkConst ``Int.Linear.eq_def_norm) ( getContext)
(toExpr x) ( mkPolyDecl p) ( mkPolyDecl p') ( mkPolyDecl c'.p)
reflBoolTrue ( mkEqRefl e) h
eagerReflBoolTrue ( mkEqRefl e) h
| .defnNatCommRing h₁ x e' p re rp p' =>
let h₂ := mkApp4 (mkConst ``Grind.CommRing.norm_int) ( getRingContext) ( mkRingExprDecl re) ( mkRingPolyDecl rp) reflBoolTrue
let h₂ := mkApp4 (mkConst ``Grind.CommRing.norm_int) ( getRingContext) ( mkRingExprDecl re) ( mkRingPolyDecl rp) eagerReflBoolTrue
return mkApp9 (mkConst ``Int.Linear.eq_def'_norm) ( getContext) (toExpr x) ( mkExprDecl e')
( mkPolyDecl p) ( mkPolyDecl p') ( mkPolyDecl c'.p) reflBoolTrue h₁ h₂
( mkPolyDecl p) ( mkPolyDecl p') ( mkPolyDecl c'.p) eagerReflBoolTrue h₁ h₂
partial def DvdCnstr.toExprProof (c' : DvdCnstr) : ProofM Expr := caching c' do
trace[grind.debug.cutsat.proof] "{← c'.pp}"
@@ -195,15 +195,15 @@ partial def DvdCnstr.toExprProof (c' : DvdCnstr) : ProofM Expr := caching c' do
mkOfEqTrue ( mkEqTrueProof e)
| .coreOfNat e thm d a' =>
let h := mkApp thm ( mkOfEqTrue ( mkEqTrueProof e))
return mkApp6 (mkConst ``Int.Linear.dvd_norm_expr) ( getContext) (toExpr (Int.ofNat d)) ( mkExprDecl a') ( mkPolyDecl c'.p) reflBoolTrue h
return mkApp6 (mkConst ``Int.Linear.dvd_norm_expr) ( getContext) (toExpr (Int.ofNat d)) ( mkExprDecl a') ( mkPolyDecl c'.p) eagerReflBoolTrue h
| .norm c =>
return mkApp6 (mkConst ``Int.Linear.dvd_norm) ( getContext) (toExpr c.d) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) reflBoolTrue ( c.toExprProof)
return mkApp6 (mkConst ``Int.Linear.dvd_norm) ( getContext) (toExpr c.d) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) eagerReflBoolTrue ( c.toExprProof)
| .elim c =>
return mkApp7 (mkConst ``Int.Linear.dvd_elim) ( getContext) (toExpr c.d) ( mkPolyDecl c.p) (toExpr c'.d) ( mkPolyDecl c'.p) reflBoolTrue ( c.toExprProof)
return mkApp7 (mkConst ``Int.Linear.dvd_elim) ( getContext) (toExpr c.d) ( mkPolyDecl c.p) (toExpr c'.d) ( mkPolyDecl c'.p) eagerReflBoolTrue ( c.toExprProof)
| .divCoeffs c =>
let g := c.p.gcdCoeffs c.d
let g := if c.d < 0 then -g else g
return mkApp8 (mkConst ``Int.Linear.dvd_coeff) ( getContext) (toExpr c.d) ( mkPolyDecl c.p) (toExpr c'.d) ( mkPolyDecl c'.p) (toExpr g) reflBoolTrue ( c.toExprProof)
return mkApp8 (mkConst ``Int.Linear.dvd_coeff) ( getContext) (toExpr c.d) ( mkPolyDecl c.p) (toExpr c'.d) ( mkPolyDecl c'.p) (toExpr g) eagerReflBoolTrue ( c.toExprProof)
| .solveCombine c₁ c₂ =>
let (d₁, a₁) c₁.get_d_a
let (d₂, a₂) c₂.get_d_a
@@ -211,19 +211,19 @@ partial def DvdCnstr.toExprProof (c' : DvdCnstr) : ProofM Expr := caching c' do
let r := mkApp10 (mkConst ``Int.Linear.dvd_solve_combine)
( getContext) (toExpr c₁.d) ( mkPolyDecl c₁.p) (toExpr c₂.d) ( mkPolyDecl c₂.p) (toExpr c'.d) ( mkPolyDecl c'.p)
(toExpr g) (toExpr α) (toExpr β)
return mkApp3 r reflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
return mkApp3 r eagerReflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
| .solveElim c₁ c₂ =>
return mkApp10 (mkConst ``Int.Linear.dvd_solve_elim)
( getContext) (toExpr c₁.d) ( mkPolyDecl c₁.p) (toExpr c₂.d) ( mkPolyDecl c₂.p) (toExpr c'.d) ( mkPolyDecl c'.p)
reflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
eagerReflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
| .ofEq x c =>
return mkApp7 (mkConst ``Int.Linear.dvd_of_eq)
( getContext) (toExpr x) ( mkPolyDecl c.p) (toExpr c'.d) ( mkPolyDecl c'.p)
reflBoolTrue ( c.toExprProof)
eagerReflBoolTrue ( c.toExprProof)
| .subst x c₁ c₂ =>
return mkApp10 (mkConst ``Int.Linear.eq_dvd_subst)
( getContext) (toExpr x) ( mkPolyDecl c₁.p) (toExpr c₂.d) ( mkPolyDecl c₂.p) (toExpr c'.d) ( mkPolyDecl c'.p)
reflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
eagerReflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
| .cooper₁ s =>
let { c₁, c₂, c₃?, left } := s.pred
let p₁ := c₁.p
@@ -232,12 +232,12 @@ partial def DvdCnstr.toExprProof (c' : DvdCnstr) : ProofM Expr := caching c' do
| none =>
let thmName := if left then ``Int.Linear.cooper_left_split_dvd else ``Int.Linear.cooper_right_split_dvd
return mkApp8 (mkConst thmName)
( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂) (toExpr s.k) (toExpr c'.d) ( mkPolyDecl c'.p) ( s.toExprProof) reflBoolTrue
( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂) (toExpr s.k) (toExpr c'.d) ( mkPolyDecl c'.p) ( s.toExprProof) eagerReflBoolTrue
| some c₃ =>
let thmName := if left then ``Int.Linear.cooper_dvd_left_split_dvd1 else ``Int.Linear.cooper_dvd_right_split_dvd1
return mkApp10 (mkConst thmName)
( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂) ( mkPolyDecl c₃.p) (toExpr c₃.d) (toExpr s.k) (toExpr c'.d) ( mkPolyDecl c'.p)
( s.toExprProof) reflBoolTrue
( s.toExprProof) eagerReflBoolTrue
| .cooper₂ s =>
let { c₁, c₂, c₃?, left } := s.pred
let p₁ := c₁.p
@@ -246,10 +246,10 @@ partial def DvdCnstr.toExprProof (c' : DvdCnstr) : ProofM Expr := caching c' do
let thmName := if left then ``Int.Linear.cooper_dvd_left_split_dvd2 else ``Int.Linear.cooper_dvd_right_split_dvd2
return mkApp10 (mkConst thmName)
( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂) ( mkPolyDecl c₃.p) (toExpr c₃.d) (toExpr s.k) (toExpr c'.d) ( mkPolyDecl c'.p)
( s.toExprProof) reflBoolTrue
( s.toExprProof) eagerReflBoolTrue
| .reorder c => withUnordered <| c.toExprProof
| .commRingNorm c e p =>
let h := mkApp4 (mkConst ``Grind.CommRing.norm_int) ( getRingContext) ( mkRingExprDecl e) ( mkRingPolyDecl p) reflBoolTrue
let h := mkApp4 (mkConst ``Grind.CommRing.norm_int) ( getRingContext) ( mkRingExprDecl e) ( mkRingPolyDecl p) eagerReflBoolTrue
return mkApp6 (mkConst ``Int.Linear.dvd_norm_poly) ( getContext) (toExpr c.d) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) h ( c.toExprProof)
partial def LeCnstr.toExprProof (c' : LeCnstr) : ProofM Expr := caching c' do
@@ -259,30 +259,30 @@ partial def LeCnstr.toExprProof (c' : LeCnstr) : ProofM Expr := caching c' do
mkOfEqTrue ( mkEqTrueProof e)
| .coreNeg e p =>
let h mkOfEqFalse ( mkEqFalseProof e)
return mkApp5 (mkConst ``Int.Linear.le_neg) ( getContext) ( mkPolyDecl p) ( mkPolyDecl c'.p) reflBoolTrue h
return mkApp5 (mkConst ``Int.Linear.le_neg) ( getContext) ( mkPolyDecl p) ( mkPolyDecl c'.p) eagerReflBoolTrue h
| .coreToInt e pos toIntThm lhs rhs =>
let h if pos then pure <| mkOfEqTrueCore e ( mkEqTrueProof e) else pure <| mkOfEqFalseCore e ( mkEqFalseProof e)
let h := mkApp toIntThm h
return mkApp6 (mkConst ``Int.Linear.le_norm_expr) ( getContext) ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c'.p) reflBoolTrue h
return mkApp6 (mkConst ``Int.Linear.le_norm_expr) ( getContext) ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c'.p) eagerReflBoolTrue h
| .ofNatNonneg a =>
return mkApp (mkConst ``Nat.ToInt.toNat_nonneg) a
| .bound h => return h
| .dec h =>
return mkFVar h
| .norm c =>
return mkApp5 (mkConst ``Int.Linear.le_norm) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) reflBoolTrue ( c.toExprProof)
return mkApp5 (mkConst ``Int.Linear.le_norm) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) eagerReflBoolTrue ( c.toExprProof)
| .divCoeffs c =>
let k := c.p.gcdCoeffs'
return mkApp6 (mkConst ``Int.Linear.le_coeff) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) (toExpr (Int.ofNat k)) reflBoolTrue ( c.toExprProof)
return mkApp6 (mkConst ``Int.Linear.le_coeff) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) (toExpr (Int.ofNat k)) eagerReflBoolTrue ( c.toExprProof)
| .combine c₁ c₂ =>
return mkApp7 (mkConst ``Int.Linear.le_combine)
( getContext) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c'.p)
reflBoolTrue
eagerReflBoolTrue
( c₁.toExprProof) ( c₂.toExprProof)
| .combineDivCoeffs c₁ c₂ k =>
return mkApp8 (mkConst ``Int.Linear.le_combine_coeff)
( getContext) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c'.p) (toExpr k)
reflBoolTrue
eagerReflBoolTrue
( c₁.toExprProof) ( c₂.toExprProof)
| .subst x c₁ c₂ =>
let a := c₁.p.coeff x
@@ -292,26 +292,26 @@ partial def LeCnstr.toExprProof (c' : LeCnstr) : ProofM Expr := caching c' do
mkConst ``Int.Linear.eq_le_subst_nonpos
return mkApp8 thm
( getContext) (toExpr x) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c'.p)
reflBoolTrue
eagerReflBoolTrue
( c₁.toExprProof) ( c₂.toExprProof)
| .ofLeDiseq c₁ c₂ =>
return mkApp7 (mkConst ``Int.Linear.le_of_le_diseq)
( getContext) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c'.p)
reflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
eagerReflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
| .dvdTight c₁ c₂ =>
return mkApp8 (mkConst ``Int.Linear.dvd_le_tight)
( getContext) (toExpr c₁.d) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c'.p)
reflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
eagerReflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
| .negDvdTight c₁ c₂ =>
return mkApp8 (mkConst ``Int.Linear.dvd_neg_le_tight)
( getContext) (toExpr c₁.d) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c'.p)
reflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
eagerReflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
| .ofDiseqSplit c₁ fvarId h _ =>
let p₂ := c₁.p.addConst 1
let hFalse h.toExprProofCore
let hNot := mkLambda `h .default (mkIntLE ( p₂.denoteExpr') (mkIntLit 0)) (hFalse.abstract #[mkFVar fvarId])
return mkApp7 (mkConst ``Int.Linear.diseq_split_resolve)
( getContext) ( mkPolyDecl c₁.p) ( mkPolyDecl p₂) ( mkPolyDecl c'.p) reflBoolTrue ( c₁.toExprProof) hNot
( getContext) ( mkPolyDecl c₁.p) ( mkPolyDecl p₂) ( mkPolyDecl c'.p) eagerReflBoolTrue ( c₁.toExprProof) hNot
| .cooper s =>
let { c₁, c₂, c₃?, left } := s.pred
let p₁ := c₁.p
@@ -321,14 +321,14 @@ partial def LeCnstr.toExprProof (c' : LeCnstr) : ProofM Expr := caching c' do
| none =>
let thmName := if left then ``Int.Linear.cooper_left_split_ineq else ``Int.Linear.cooper_right_split_ineq
return mkApp8 (mkConst thmName)
( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂) (toExpr s.k) (toExpr coeff) ( mkPolyDecl c'.p) ( s.toExprProof) reflBoolTrue
( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂) (toExpr s.k) (toExpr coeff) ( mkPolyDecl c'.p) ( s.toExprProof) eagerReflBoolTrue
| some c₃ =>
let thmName := if left then ``Int.Linear.cooper_dvd_left_split_ineq else ``Int.Linear.cooper_dvd_right_split_ineq
return mkApp10 (mkConst thmName)
( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂) ( mkPolyDecl c₃.p) (toExpr c₃.d) (toExpr s.k) (toExpr coeff) ( mkPolyDecl c'.p) ( s.toExprProof) reflBoolTrue
( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂) ( mkPolyDecl c₃.p) (toExpr c₃.d) (toExpr s.k) (toExpr coeff) ( mkPolyDecl c'.p) ( s.toExprProof) eagerReflBoolTrue
| .reorder c => withUnordered <| c.toExprProof
| .commRingNorm c e p =>
let h := mkApp4 (mkConst ``Grind.CommRing.norm_int) ( getRingContext) ( mkRingExprDecl e) ( mkRingPolyDecl p) reflBoolTrue
let h := mkApp4 (mkConst ``Grind.CommRing.norm_int) ( getRingContext) ( mkRingExprDecl e) ( mkRingPolyDecl p) eagerReflBoolTrue
return mkApp5 (mkConst ``Int.Linear.le_norm_poly) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) h ( c.toExprProof)
partial def DiseqCnstr.toExprProof (c' : DiseqCnstr) : ProofM Expr := caching c' do
@@ -337,24 +337,24 @@ partial def DiseqCnstr.toExprProof (c' : DiseqCnstr) : ProofM Expr := caching c'
mkDiseqProof a zero
| .core a b p₁ p₂ =>
let h mkDiseqProof a b
return mkApp6 (mkConst ``Int.Linear.diseq_of_core) ( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂) ( mkPolyDecl c'.p) reflBoolTrue h
return mkApp6 (mkConst ``Int.Linear.diseq_of_core) ( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂) ( mkPolyDecl c'.p) eagerReflBoolTrue h
| .coreToInt a b toIntThm lhs rhs =>
let h := mkApp toIntThm ( mkDiseqProof a b)
return mkApp6 (mkConst ``Int.Linear.not_eq_norm_expr) ( getContext) ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c'.p) reflBoolTrue h
return mkApp6 (mkConst ``Int.Linear.not_eq_norm_expr) ( getContext) ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c'.p) eagerReflBoolTrue h
| .norm c =>
return mkApp5 (mkConst ``Int.Linear.diseq_norm) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) reflBoolTrue ( c.toExprProof)
return mkApp5 (mkConst ``Int.Linear.diseq_norm) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) eagerReflBoolTrue ( c.toExprProof)
| .divCoeffs c =>
let k := c.p.gcdCoeffs c.p.getConst
return mkApp6 (mkConst ``Int.Linear.diseq_coeff) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) (toExpr k) reflBoolTrue ( c.toExprProof)
return mkApp6 (mkConst ``Int.Linear.diseq_coeff) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) (toExpr k) eagerReflBoolTrue ( c.toExprProof)
| .neg c =>
return mkApp5 (mkConst ``Int.Linear.diseq_neg) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) reflBoolTrue ( c.toExprProof)
return mkApp5 (mkConst ``Int.Linear.diseq_neg) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) eagerReflBoolTrue ( c.toExprProof)
| .subst x c₁ c₂ =>
return mkApp8 (mkConst ``Int.Linear.eq_diseq_subst)
( getContext) (toExpr x) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c'.p)
reflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
eagerReflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
| .reorder c => withUnordered <| c.toExprProof
| .commRingNorm c e p =>
let h := mkApp4 (mkConst ``Grind.CommRing.norm_int) ( getRingContext) ( mkRingExprDecl e) ( mkRingPolyDecl p) reflBoolTrue
let h := mkApp4 (mkConst ``Grind.CommRing.norm_int) ( getRingContext) ( mkRingExprDecl e) ( mkRingPolyDecl p) eagerReflBoolTrue
return mkApp5 (mkConst ``Int.Linear.diseq_norm_poly) ( getContext) ( mkPolyDecl c.p) ( mkPolyDecl c'.p) h ( c.toExprProof)
partial def CooperSplit.toExprProof (s : CooperSplit) : ProofM Expr := caching s do
@@ -372,14 +372,14 @@ partial def CooperSplit.toExprProof (s : CooperSplit) : ProofM Expr := caching s
let thmName := if left then ``Int.Linear.cooper_left else ``Int.Linear.cooper_right
let predName := if left then ``Int.Linear.cooper_left_split else ``Int.Linear.cooper_right_split
let base := mkApp7 (mkConst thmName) ( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂) (toExpr n)
reflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
eagerReflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
let pred := mkApp3 (mkConst predName) ( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂)
pure (base, pred)
| some c₃ =>
let thmName := if left then ``Int.Linear.cooper_dvd_left else ``Int.Linear.cooper_dvd_right
let predName := if left then ``Int.Linear.cooper_dvd_left_split else ``Int.Linear.cooper_dvd_right_split
let base := mkApp10 (mkConst thmName) ( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂) ( mkPolyDecl c₃.p) (toExpr c₃.d) (toExpr n)
reflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof) ( c₃.toExprProof)
eagerReflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof) ( c₃.toExprProof)
let pred := mkApp5 (mkConst predName) ( getContext) ( mkPolyDecl p₁) ( mkPolyDecl p₂) ( mkPolyDecl c₃.p) (toExpr c₃.d)
pure (base, pred)
-- `pred` is an expressions of the form `cooper_*_split ...` with type `Nat → Prop`
@@ -399,23 +399,23 @@ partial def CooperSplit.toExprProof (s : CooperSplit) : ProofM Expr := caching s
partial def UnsatProof.toExprProofCore (h : UnsatProof) : ProofM Expr := do
match h with
| .le c =>
return mkApp4 (mkConst ``Int.Linear.le_unsat) ( getContext) ( mkPolyDecl c.p) reflBoolTrue ( c.toExprProof)
return mkApp4 (mkConst ``Int.Linear.le_unsat) ( getContext) ( mkPolyDecl c.p) eagerReflBoolTrue ( c.toExprProof)
| .dvd c =>
return mkApp5 (mkConst ``Int.Linear.dvd_unsat) ( getContext) (toExpr c.d) ( mkPolyDecl c.p) reflBoolTrue ( c.toExprProof)
return mkApp5 (mkConst ``Int.Linear.dvd_unsat) ( getContext) (toExpr c.d) ( mkPolyDecl c.p) eagerReflBoolTrue ( c.toExprProof)
| .eq c =>
if c.p.isUnsatEq then
return mkApp4 (mkConst ``Int.Linear.eq_unsat) ( getContext) ( mkPolyDecl c.p) reflBoolTrue ( c.toExprProof)
return mkApp4 (mkConst ``Int.Linear.eq_unsat) ( getContext) ( mkPolyDecl c.p) eagerReflBoolTrue ( c.toExprProof)
else
let k := c.p.gcdCoeffs'
return mkApp5 (mkConst ``Int.Linear.eq_unsat_coeff) ( getContext) ( mkPolyDecl c.p) (toExpr (Int.ofNat k)) reflBoolTrue ( c.toExprProof)
return mkApp5 (mkConst ``Int.Linear.eq_unsat_coeff) ( getContext) ( mkPolyDecl c.p) (toExpr (Int.ofNat k)) eagerReflBoolTrue ( c.toExprProof)
| .diseq c =>
return mkApp4 (mkConst ``Int.Linear.diseq_unsat) ( getContext) ( mkPolyDecl c.p) reflBoolTrue ( c.toExprProof)
return mkApp4 (mkConst ``Int.Linear.diseq_unsat) ( getContext) ( mkPolyDecl c.p) eagerReflBoolTrue ( c.toExprProof)
| .cooper c₁ c₂ c₃ =>
let .add c _ _ := c₃.p | c₃.throwUnexpected
let d := c₃.d
let (_, α, β) := gcdExt c d
let h := mkApp7 (mkConst ``Int.Linear.cooper_unsat) ( getContext) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c₃.p) (toExpr c₃.d) (toExpr α) (toExpr β)
return mkApp4 h reflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof) ( c₃.toExprProof)
return mkApp4 h eagerReflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof) ( c₃.toExprProof)
end

View File

@@ -63,19 +63,19 @@ where
let toInt := mkApp3 (mkConst ``Grind.ToInt.toInt [u]) type rangeExpr toIntInst
let wrap := mkApp (mkConst ``Grind.IntInterval.wrap) rangeExpr
let ofWrap0? := if let .co 0 hi := range then
some <| mkApp3 (mkConst ``Grind.ToInt.of_eq_wrap_co_0) rangeExpr (toExpr hi) reflBoolTrue
some <| mkApp3 (mkConst ``Grind.ToInt.of_eq_wrap_co_0) rangeExpr (toExpr hi) eagerReflBoolTrue
else
none
let ofEq := mkApp3 (mkConst ``Grind.ToInt.of_eq [u]) type rangeExpr toIntInst
let ofDiseq := mkApp3 (mkConst ``Grind.ToInt.of_diseq [u]) type rangeExpr toIntInst
let lowerThm? := if let some lo := range.lo? then
if lo == 0 then
some <| mkApp4 (mkConst ``Grind.ToInt.ge_lower0 [u]) type rangeExpr toIntInst reflBoolTrue
some <| mkApp4 (mkConst ``Grind.ToInt.ge_lower0 [u]) type rangeExpr toIntInst eagerReflBoolTrue
else
some <| mkApp5 (mkConst ``Grind.ToInt.ge_lower [u]) type rangeExpr toIntInst (toExpr lo) reflBoolTrue
some <| mkApp5 (mkConst ``Grind.ToInt.ge_lower [u]) type rangeExpr toIntInst (toExpr lo) eagerReflBoolTrue
else none
let upperThm? := if let some hi := range.hi? then
some <| mkApp5 (mkConst ``Grind.ToInt.le_upper [u]) type rangeExpr toIntInst (toExpr (-hi + 1)) reflBoolTrue
some <| mkApp5 (mkConst ``Grind.ToInt.le_upper [u]) type rangeExpr toIntInst (toExpr (-hi + 1)) eagerReflBoolTrue
else none
trace[grind.debug.cutsat.toInt] "registered toInt: {type}"
let id := ( get').toIntInfos.size
@@ -187,15 +187,15 @@ private def mkBinOpThms (opBaseName : Name) (thmName : Name) : ToIntM ToIntThms
let cwrName := thmName ++ `wr
let info getInfo
let c_ww? := if info.range.isFinite && env.contains cwwName then
some <| mkApp6 (mkConst cwwName [info.u]) info.type info.rangeExpr info.toIntInst opInst toIntOpInst reflBoolTrue
some <| mkApp6 (mkConst cwwName [info.u]) info.type info.rangeExpr info.toIntInst opInst toIntOpInst eagerReflBoolTrue
else
none
let c_wl? := if info.range.isFinite && info.range.nonEmpty && env.contains cwwName then
some <| mkApp7 (mkConst cwlName [info.u]) info.type info.rangeExpr info.toIntInst opInst toIntOpInst reflBoolTrue reflBoolTrue
let c_wl? := if info.range.isFinite && info.range.nonEmpty && env.contains cwwName then -- TODO: nonEmpty may be unknown if symbolic bounds
some <| mkApp7 (mkConst cwlName [info.u]) info.type info.rangeExpr info.toIntInst opInst toIntOpInst eagerReflBoolTrue eagerReflBoolTrue
else
none
let c_wr? := if info.range.isFinite && info.range.nonEmpty && env.contains cwwName then
some <| mkApp7 (mkConst cwrName [info.u]) info.type info.rangeExpr info.toIntInst opInst toIntOpInst reflBoolTrue reflBoolTrue
let c_wr? := if info.range.isFinite && info.range.nonEmpty && env.contains cwwName then -- TODO: nonEmpty may be unknown if symbolic bounds
some <| mkApp7 (mkConst cwrName [info.u]) info.type info.rangeExpr info.toIntInst opInst toIntOpInst eagerReflBoolTrue eagerReflBoolTrue
else
none
return { c? := some c, c_ww?, c_wl?, c_wr? }

View File

@@ -192,20 +192,20 @@ partial def IneqCnstr.toExprProof (c' : IneqCnstr) : ProofM Expr := caching c' d
match c'.h with
| .core e lhs rhs =>
let h mkIntModPreOrdThmPrefix (if c'.strict then ``Grind.Linarith.lt_norm else ``Grind.Linarith.le_norm)
return mkApp5 h ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c'.p) reflBoolTrue (mkOfEqTrueCore e ( mkEqTrueProof e))
return mkApp5 h ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c'.p) eagerReflBoolTrue (mkOfEqTrueCore e ( mkEqTrueProof e))
| .notCore e lhs rhs =>
let h mkIntModLinOrdThmPrefix (if c'.strict then ``Grind.Linarith.not_le_norm else ``Grind.Linarith.not_lt_norm)
return mkApp5 h ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c'.p) reflBoolTrue (mkOfEqFalseCore e ( mkEqFalseProof e))
return mkApp5 h ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c'.p) eagerReflBoolTrue (mkOfEqFalseCore e ( mkEqFalseProof e))
| .coreCommRing e lhs rhs p' lhs' =>
let h' mkCommRingPreOrdThmPrefix (if c'.strict then ``Grind.CommRing.lt_norm else ``Grind.CommRing.le_norm)
let h' := mkApp5 h' ( mkRingExprDecl lhs) ( mkRingExprDecl rhs) ( mkRingPolyDecl p') reflBoolTrue (mkOfEqTrueCore e ( mkEqTrueProof e))
let h' := mkApp5 h' ( mkRingExprDecl lhs) ( mkRingExprDecl rhs) ( mkRingPolyDecl p') eagerReflBoolTrue (mkOfEqTrueCore e ( mkEqTrueProof e))
let h mkIntModPreOrdThmPrefix (if c'.strict then ``Grind.Linarith.lt_norm else ``Grind.Linarith.le_norm)
return mkApp5 h ( mkExprDecl lhs') ( mkExprDecl .zero) ( mkPolyDecl c'.p) reflBoolTrue h'
return mkApp5 h ( mkExprDecl lhs') ( mkExprDecl .zero) ( mkPolyDecl c'.p) eagerReflBoolTrue h'
| .notCoreCommRing e lhs rhs p' lhs' =>
let h' mkCommRingLinOrdThmPrefix (if c'.strict then ``Grind.CommRing.not_le_norm else ``Grind.CommRing.not_lt_norm)
let h' := mkApp5 h' ( mkRingExprDecl lhs) ( mkRingExprDecl rhs) ( mkRingPolyDecl p') reflBoolTrue (mkOfEqFalseCore e ( mkEqFalseProof e))
let h' := mkApp5 h' ( mkRingExprDecl lhs) ( mkRingExprDecl rhs) ( mkRingPolyDecl p') eagerReflBoolTrue (mkOfEqFalseCore e ( mkEqFalseProof e))
let h mkIntModPreOrdThmPrefix (if c'.strict then ``Grind.Linarith.lt_norm else ``Grind.Linarith.le_norm)
return mkApp5 h ( mkExprDecl lhs') ( mkExprDecl .zero) ( mkPolyDecl c'.p) reflBoolTrue h'
return mkApp5 h ( mkExprDecl lhs') ( mkExprDecl .zero) ( mkPolyDecl c'.p) eagerReflBoolTrue h'
| .combine c₁ c₂ =>
let (declName, c₁, c₂) :=
match c₁.strict, c₂.strict with
@@ -213,49 +213,49 @@ partial def IneqCnstr.toExprProof (c' : IneqCnstr) : ProofM Expr := caching c' d
| true, false => (``Grind.Linarith.le_lt_combine, c₂, c₁)
| false, true => (``Grind.Linarith.le_lt_combine, c₁, c₂)
| false, false => (``Grind.Linarith.le_le_combine, c₁, c₂)
return mkApp6 ( mkIntModPreOrdThmPrefix declName) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c'.p) reflBoolTrue
return mkApp6 ( mkIntModPreOrdThmPrefix declName) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c'.p) eagerReflBoolTrue
( c₁.toExprProof) ( c₂.toExprProof)
| .oneGtZero =>
let s getStruct
let h := mkApp5 (mkConst ``Grind.Linarith.zero_lt_one [s.u]) s.type ( getRingInst) ( getPreorderInst) ( getOrderedRingInst) ( getContext)
return mkApp3 h ( mkPolyDecl c'.p) reflBoolTrue ( mkEqRefl ( getOne))
return mkApp3 h ( mkPolyDecl c'.p) eagerReflBoolTrue ( mkEqRefl ( getOne))
| .ofEq a b la lb =>
let h mkIntModPreOrdThmPrefix ``Grind.Linarith.le_of_eq
return mkApp5 h ( mkExprDecl la) ( mkExprDecl lb) ( mkPolyDecl c'.p) reflBoolTrue ( mkEqProof a b)
return mkApp5 h ( mkExprDecl la) ( mkExprDecl lb) ( mkPolyDecl c'.p) eagerReflBoolTrue ( mkEqProof a b)
| .ofCommRingEq a b la lb p' lhs' =>
let h' mkCommRingThmPrefix ``Grind.CommRing.eq_norm
let h' := mkApp5 h' ( mkRingExprDecl la) ( mkRingExprDecl lb) ( mkRingPolyDecl p') reflBoolTrue ( mkEqProof a b)
let h' := mkApp5 h' ( mkRingExprDecl la) ( mkRingExprDecl lb) ( mkRingPolyDecl p') eagerReflBoolTrue ( mkEqProof a b)
let h mkIntModPreOrdThmPrefix ``Grind.Linarith.le_of_eq
return mkApp5 h ( mkExprDecl lhs') ( mkExprDecl .zero) ( mkPolyDecl c'.p) reflBoolTrue h'
return mkApp5 h ( mkExprDecl lhs') ( mkExprDecl .zero) ( mkPolyDecl c'.p) eagerReflBoolTrue h'
| .dec h => return mkFVar h
| .ofDiseqSplit c₁ fvarId h _ =>
let hFalse h.toExprProofCore
let lt getLtFn
let hNot := mkLambda `h .default (mkApp2 lt ( c₁.p.denoteExpr) ( getZero)) (hFalse.abstract #[mkFVar fvarId])
let h mkIntModLinOrdThmPrefix ``Grind.Linarith.diseq_split_resolve
return mkApp5 h ( mkPolyDecl c₁.p) ( mkPolyDecl c'.p) reflBoolTrue ( c₁.toExprProof) hNot
return mkApp5 h ( mkPolyDecl c₁.p) ( mkPolyDecl c'.p) eagerReflBoolTrue ( c₁.toExprProof) hNot
| _ => throwError "not implemented yet"
partial def DiseqCnstr.toExprProof (c' : DiseqCnstr) : ProofM Expr := caching c' do
match c'.h with
| .core a b lhs rhs =>
let h mkIntModThmPrefix ``Grind.Linarith.diseq_norm
return mkApp5 h ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c'.p) reflBoolTrue ( mkDiseqProof a b)
return mkApp5 h ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c'.p) eagerReflBoolTrue ( mkDiseqProof a b)
| .coreCommRing a b lhs rhs p' lhs' =>
let h' mkCommRingThmPrefix ``Grind.CommRing.diseq_norm
let h' := mkApp5 h' ( mkRingExprDecl lhs) ( mkRingExprDecl rhs) ( mkRingPolyDecl p') reflBoolTrue ( mkDiseqProof a b)
let h' := mkApp5 h' ( mkRingExprDecl lhs) ( mkRingExprDecl rhs) ( mkRingPolyDecl p') eagerReflBoolTrue ( mkDiseqProof a b)
let h mkIntModThmPrefix ``Grind.Linarith.diseq_norm
return mkApp5 h ( mkExprDecl lhs') ( mkExprDecl .zero) ( mkPolyDecl c'.p) reflBoolTrue h'
return mkApp5 h ( mkExprDecl lhs') ( mkExprDecl .zero) ( mkPolyDecl c'.p) eagerReflBoolTrue h'
| .neg c =>
let h mkIntModThmPrefix ``Grind.Linarith.diseq_neg
return mkApp4 h ( mkPolyDecl c.p) ( mkPolyDecl c'.p) reflBoolTrue ( c.toExprProof)
return mkApp4 h ( mkPolyDecl c.p) ( mkPolyDecl c'.p) eagerReflBoolTrue ( c.toExprProof)
| .subst k₁ k₂ c₁ c₂ =>
let h mkIntModNoNatDivThmPrefix ``Grind.Linarith.eq_diseq_subst
return mkApp8 h (toExpr k₁) (toExpr k₂) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c'.p)
reflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
eagerReflBoolTrue ( c₁.toExprProof) ( c₂.toExprProof)
| .subst1 k c₁ c₂ =>
let h mkIntModThmPrefix ``Grind.Linarith.eq_diseq_subst1
return mkApp7 h (toExpr k) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c'.p) reflBoolTrue
return mkApp7 h (toExpr k) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c'.p) eagerReflBoolTrue
( c₁.toExprProof) ( c₂.toExprProof)
| .oneNeZero => throwError "not implemented yet"
@@ -263,17 +263,17 @@ partial def EqCnstr.toExprProof (c' : EqCnstr) : ProofM Expr := caching c' do
match c'.h with
| .core a b lhs rhs =>
let h mkIntModThmPrefix ``Grind.Linarith.eq_norm
return mkApp5 h ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c'.p) reflBoolTrue ( mkEqProof a b)
return mkApp5 h ( mkExprDecl lhs) ( mkExprDecl rhs) ( mkPolyDecl c'.p) eagerReflBoolTrue ( mkEqProof a b)
| .coreCommRing .. => throwError "not implemented yet"
| .neg c =>
let h mkIntModThmPrefix ``Grind.Linarith.eq_neg
return mkApp4 h ( mkPolyDecl c.p) ( mkPolyDecl c'.p) reflBoolTrue ( c.toExprProof)
return mkApp4 h ( mkPolyDecl c.p) ( mkPolyDecl c'.p) eagerReflBoolTrue ( c.toExprProof)
| .coeff k c =>
let h mkIntModNoNatDivThmPrefix ``Grind.Linarith.eq_coeff
return mkApp5 h ( mkPolyDecl c.p) ( mkPolyDecl c'.p) (toExpr k) reflBoolTrue ( c.toExprProof)
return mkApp5 h ( mkPolyDecl c.p) ( mkPolyDecl c'.p) (toExpr k) eagerReflBoolTrue ( c.toExprProof)
| .subst x c₁ c₂ =>
let h mkIntModThmPrefix ``Grind.Linarith.eq_eq_subst
return mkApp7 h (toExpr x) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c'.p) reflBoolTrue
return mkApp7 h (toExpr x) ( mkPolyDecl c₁.p) ( mkPolyDecl c₂.p) ( mkPolyDecl c'.p) eagerReflBoolTrue
( c₁.toExprProof) ( c₂.toExprProof)
partial def UnsatProof.toExprProofCore (h : UnsatProof) : ProofM Expr := do

View File

@@ -83,7 +83,7 @@ private def closeGoalWithValuesEq (lhs rhs : Expr) : GoalM Unit := do
let p mkEq lhs rhs
let hp mkEqProof lhs rhs
let d mkDecide p
let pEqFalse := mkApp3 (mkConst ``eq_false_of_decide) p d.appArg! reflBoolFalse
let pEqFalse := mkApp3 (mkConst ``eq_false_of_decide) p d.appArg! eagerReflBoolFalse
let falseProof := mkApp4 (mkConst ``Eq.mp [levelZero]) p ( getFalseExpr) pEqFalse hp
closeGoal falseProof

View File

@@ -40,37 +40,37 @@ def simpEq? (e : Expr) : MetaM (Option (Expr × Expr)) := do
let p := a.sub b |>.norm
if p.isUnsatEq then
let r := mkConst ``False
let h := mkApp4 (mkConst ``Int.Linear.eq_eq_false) ( toContextExpr atoms) (toExpr a) (toExpr b) reflBoolTrue
let h := mkApp4 (mkConst ``Int.Linear.eq_eq_false) ( toContextExpr atoms) (toExpr a) (toExpr b) eagerReflBoolTrue
return some (r, mkExpectedPropHint h (mkPropEq e r))
else if p.isValidEq then
let r := mkConst ``True
let h := mkApp4 (mkConst ``Int.Linear.eq_eq_true) ( toContextExpr atoms) (toExpr a) (toExpr b) reflBoolTrue
let h := mkApp4 (mkConst ``Int.Linear.eq_eq_true) ( toContextExpr atoms) (toExpr a) (toExpr b) eagerReflBoolTrue
return some (r, mkExpectedPropHint h (mkPropEq e r))
else if p.toExpr == a && b == .num 0 then
return none
else match p with
| .add 1 x (.add (-1) y (.num 0)) =>
let r := mkIntEq atoms[x]! atoms[y]!
let h := mkApp6 (mkConst ``Int.Linear.norm_eq_var) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr x) (toExpr y) reflBoolTrue
let h := mkApp6 (mkConst ``Int.Linear.norm_eq_var) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr x) (toExpr y) eagerReflBoolTrue
return some (r, mkExpectedPropHint h (mkPropEq e r))
| .add 1 x (.num k) =>
let r := mkIntEq atoms[x]! (toExpr (-k))
let h := mkApp6 (mkConst ``Int.Linear.norm_eq_var_const) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr x) (toExpr (-k)) reflBoolTrue
let h := mkApp6 (mkConst ``Int.Linear.norm_eq_var_const) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr x) (toExpr (-k)) eagerReflBoolTrue
return some (r, mkExpectedPropHint h (mkPropEq e r))
| _ =>
let k := p.gcdCoeffs'
if k == 1 then
let r := mkIntEq ( p.denoteExpr (atoms[·]!)) (mkIntLit 0)
let h := mkApp5 (mkConst ``Int.Linear.norm_eq) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr p) reflBoolTrue
let h := mkApp5 (mkConst ``Int.Linear.norm_eq) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr p) eagerReflBoolTrue
return some (r, mkExpectedPropHint h (mkPropEq e r))
else if p.getConst % k == 0 then
let p := p.div k
let r := mkIntEq ( p.denoteExpr (atoms[·]!)) (mkIntLit 0)
let h := mkApp6 (mkConst ``Int.Linear.norm_eq_coeff) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr p) (toExpr (Int.ofNat k)) reflBoolTrue
let h := mkApp6 (mkConst ``Int.Linear.norm_eq_coeff) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr p) (toExpr (Int.ofNat k)) eagerReflBoolTrue
return some (r, mkExpectedPropHint h (mkPropEq e r))
else
let r := mkConst ``False
let h := mkApp5 (mkConst ``Int.Linear.eq_eq_false_of_divCoeff) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr (Int.ofNat k)) reflBoolTrue
let h := mkApp5 (mkConst ``Int.Linear.eq_eq_false_of_divCoeff) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr (Int.ofNat k)) eagerReflBoolTrue
return some (r, mkExpectedPropHint h (mkPropEq e r))
@@ -83,11 +83,11 @@ def simpLe? (e : Expr) (checkIfModified : Bool) : MetaM (Option (Expr × Expr))
let p := a.sub b |>.norm
if p.isUnsatLe then
let r := mkConst ``False
let h := mkApp4 (mkConst ``Int.Linear.le_eq_false) ( toContextExpr atoms) (toExpr a) (toExpr b) reflBoolTrue
let h := mkApp4 (mkConst ``Int.Linear.le_eq_false) ( toContextExpr atoms) (toExpr a) (toExpr b) eagerReflBoolTrue
return some (r, mkExpectedPropHint h (mkPropEq e r))
else if p.isValidLe then
let r := mkConst ``True
let h := mkApp4 (mkConst ``Int.Linear.le_eq_true) ( toContextExpr atoms) (toExpr a) (toExpr b) reflBoolTrue
let h := mkApp4 (mkConst ``Int.Linear.le_eq_true) ( toContextExpr atoms) (toExpr a) (toExpr b) eagerReflBoolTrue
return some (r, mkExpectedPropHint h (mkPropEq e r))
else if checkIfModified && p.toExpr == a && b == .num 0 then
return none
@@ -95,16 +95,16 @@ def simpLe? (e : Expr) (checkIfModified : Bool) : MetaM (Option (Expr × Expr))
let k := p.gcdCoeffs'
if k == 1 then
let r := mkIntLE ( p.denoteExpr (atoms[·]!)) (mkIntLit 0)
let h := mkApp5 (mkConst ``Int.Linear.norm_le) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr p) reflBoolTrue
let h := mkApp5 (mkConst ``Int.Linear.norm_le) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr p) eagerReflBoolTrue
return some (r, mkExpectedPropHint h (mkPropEq e r))
else
let tight := p.getConst % k != 0
let p := p.div k
let r := mkIntLE ( p.denoteExpr (atoms[·]!)) (mkIntLit 0)
let h if tight then
pure <| mkApp6 (mkConst ``Int.Linear.norm_le_coeff_tight) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr p) (toExpr (Int.ofNat k)) reflBoolTrue
pure <| mkApp6 (mkConst ``Int.Linear.norm_le_coeff_tight) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr p) (toExpr (Int.ofNat k)) eagerReflBoolTrue
else
pure <| mkApp6 (mkConst ``Int.Linear.norm_le_coeff) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr p) (toExpr (Int.ofNat k)) reflBoolTrue
pure <| mkApp6 (mkConst ``Int.Linear.norm_le_coeff) ( toContextExpr atoms) (toExpr a) (toExpr b) (toExpr p) (toExpr (Int.ofNat k)) eagerReflBoolTrue
return some (r, mkExpectedPropHint h (mkPropEq e r))
def simpRel? (e : Expr) : MetaM (Option (Expr × Expr)) := do
@@ -150,13 +150,13 @@ def simpDvd? (e : Expr) : MetaM (Option (Expr × Expr)) := do
return none
let rhs := mkIntDvd (toExpr d') ( p.denoteExpr (atoms[·]!))
let h if g == 1 then
pure <| mkApp5 (mkConst ``Int.Linear.norm_dvd) ( toContextExpr atoms) (toExpr d) (toExpr e) (toExpr p) reflBoolTrue
pure <| mkApp5 (mkConst ``Int.Linear.norm_dvd) ( toContextExpr atoms) (toExpr d) (toExpr e) (toExpr p) eagerReflBoolTrue
else
pure <| mkApp7 (mkConst ``Int.Linear.norm_dvd_gcd) ( toContextExpr atoms) (toExpr d) (toExpr e) (toExpr d') (toExpr p) (toExpr g) reflBoolTrue
pure <| mkApp7 (mkConst ``Int.Linear.norm_dvd_gcd) ( toContextExpr atoms) (toExpr d) (toExpr e) (toExpr d') (toExpr p) (toExpr g) eagerReflBoolTrue
return some (rhs, mkExpectedPropHint h (mkPropEq lhs rhs))
else
let rhs := mkConst ``False
let h := mkApp4 (mkConst ``Int.Linear.dvd_eq_false) ( toContextExpr atoms) (toExpr d) (toExpr e) reflBoolTrue
let h := mkApp4 (mkConst ``Int.Linear.dvd_eq_false) ( toContextExpr atoms) (toExpr d) (toExpr e) eagerReflBoolTrue
return some (rhs, mkExpectedPropHint h (mkPropEq lhs rhs))
def simpExpr? (lhs : Expr) : MetaM (Option (Expr × Expr)) := do
@@ -165,7 +165,7 @@ def simpExpr? (lhs : Expr) : MetaM (Option (Expr × Expr)) := do
let p := e.norm
let e' := p.toExpr
if e != e' then
let h := mkApp4 (mkConst ``Int.Linear.Expr.eq_of_norm_eq) ( toContextExpr ctx) (toExpr e) (toExpr p) reflBoolTrue
let h := mkApp4 (mkConst ``Int.Linear.Expr.eq_of_norm_eq) ( toContextExpr ctx) (toExpr e) (toExpr p) eagerReflBoolTrue
let lhs e.denoteExpr (ctx[·]!)
let rhs p.denoteExpr (ctx[·]!)
return some (rhs, mkExpectedPropHint h (mkIntEq lhs rhs))

View File

@@ -22,17 +22,17 @@ def simpCnstrPos? (e : Expr) : MetaM (Option (Expr × Expr)) := do
let c₂ := c₁.norm
if c₂.isUnsat then
let r := mkConst ``False
let p := mkApp3 (mkConst ``Nat.Linear.ExprCnstr.eq_false_of_isUnsat) ( toContextExpr atoms) (toExpr c) reflBoolTrue
let p := mkApp3 (mkConst ``Nat.Linear.ExprCnstr.eq_false_of_isUnsat) ( toContextExpr atoms) (toExpr c) eagerReflBoolTrue
return some (r, mkExpectedPropHint p (mkPropEq lhs r))
else if c₂.isValid then
let r := mkConst ``True
let p := mkApp3 (mkConst ``Nat.Linear.ExprCnstr.eq_true_of_isValid) ( toContextExpr atoms) (toExpr c) reflBoolTrue
let p := mkApp3 (mkConst ``Nat.Linear.ExprCnstr.eq_true_of_isValid) ( toContextExpr atoms) (toExpr c) eagerReflBoolTrue
return some (r, mkExpectedPropHint p (mkPropEq lhs r))
else
let c₂ : LinearCnstr := c₂.toExpr
let r c₂.toArith atoms
if r != lhs then
let p := mkApp4 (mkConst ``Nat.Linear.ExprCnstr.eq_of_toNormPoly_eq) ( toContextExpr atoms) (toExpr c) (toExpr c₂) reflBoolTrue
let p := mkApp4 (mkConst ``Nat.Linear.ExprCnstr.eq_of_toNormPoly_eq) ( toContextExpr atoms) (toExpr c) (toExpr c₂) eagerReflBoolTrue
return some (r, mkExpectedPropHint p (mkPropEq lhs r))
else
return none
@@ -74,7 +74,7 @@ def simpExpr? (input : Expr) : MetaM (Option (Expr × Expr)) := do
let e' : LinearExpr := p'.toExpr
if e' == e then
return none
let p := mkApp4 (mkConst ``Nat.Linear.Expr.eq_of_toNormPoly_eq) ( toContextExpr ctx) (toExpr e) (toExpr e') reflBoolTrue
let p := mkApp4 (mkConst ``Nat.Linear.Expr.eq_of_toNormPoly_eq) ( toContextExpr ctx) (toExpr e) (toExpr e') eagerReflBoolTrue
let l e.toArith ctx
let r e'.toArith ctx
return some (r, mkExpectedPropHint p (mkNatEq l r))

View File

@@ -118,9 +118,9 @@ builtin_simproc [simp, seval] reduceDvd ((_ : Int) _) := fun e => do
let some va fromExpr? a | return .continue
let some vb fromExpr? b | return .continue
if vb % va == 0 then
return .done { expr := mkConst ``True, proof? := mkApp3 (mkConst ``Int.dvd_eq_true_of_mod_eq_zero) a b reflBoolTrue}
return .done { expr := mkConst ``True, proof? := mkApp3 (mkConst ``Int.dvd_eq_true_of_mod_eq_zero) a b eagerReflBoolTrue}
else
return .done { expr := mkConst ``False, proof? := mkApp3 (mkConst ``Int.dvd_eq_false_of_mod_ne_zero) a b reflBoolTrue}
return .done { expr := mkConst ``False, proof? := mkApp3 (mkConst ``Int.dvd_eq_false_of_mod_ne_zero) a b eagerReflBoolTrue}
private def reduceNatCastCore (inst : Expr) (a : Expr) : SimpM DStep := do
let some a getNatValue? a | return .continue

View File

@@ -355,8 +355,8 @@ builtin_simproc [simp, seval] reduceDvd ((_ : Nat) _) := fun e => do
let some va fromExpr? a | return .continue
let some vb fromExpr? b | return .continue
if vb % va == 0 then
return .done { expr := mkConst ``True, proof? := mkApp3 (mkConst ``Nat.dvd_eq_true_of_mod_eq_zero) a b reflBoolTrue}
return .done { expr := mkConst ``True, proof? := mkApp3 (mkConst ``Nat.dvd_eq_true_of_mod_eq_zero) a b eagerReflBoolTrue}
else
return .done { expr := mkConst ``False, proof? := mkApp3 (mkConst ``Nat.dvd_eq_false_of_mod_ne_zero) a b reflBoolTrue}
return .done { expr := mkConst ``False, proof? := mkApp3 (mkConst ``Nat.dvd_eq_false_of_mod_ne_zero) a b eagerReflBoolTrue}
end Nat

View File

@@ -24,6 +24,7 @@ namespace lean {
static name * g_kernel_fresh = nullptr;
static expr * g_dont_care = nullptr;
static name * g_bool_true = nullptr;
static name * g_eager_reduce = nullptr;
static expr * g_nat_zero = nullptr;
static expr * g_nat_succ = nullptr;
static expr * g_nat_add = nullptr;
@@ -154,12 +155,23 @@ expr type_checker::infer_pi(expr const & _e, bool infer_only) {
return mk_sort(r);
}
/* Returns `true` if `e` is of the form `eagerReduce _ _` */
static bool is_eager_reduce(expr const & e) {
return is_const(get_app_fn(e), *g_eager_reduce) && get_app_num_args(e) == 2;
}
expr type_checker::infer_app(expr const & e, bool infer_only) {
if (!infer_only) {
expr f_type = ensure_pi_core(infer_type_core(app_fn(e), infer_only), e);
expr a_type = infer_type_core(app_arg(e), infer_only);
expr d_type = binding_domain(f_type);
if (!is_def_eq(a_type, d_type)) {
if (is_eager_reduce(app_arg(e))) {
// If argument is of the form `eagerReduce`, set m_eager_reduction mode
flet<bool> scope(m_eager_reduce, true);
if (!is_def_eq(a_type, d_type)) {
throw app_type_mismatch_exception(env(), m_lctx, e, f_type, a_type);
}
} else if (!is_def_eq(a_type, d_type)) {
throw app_type_mismatch_exception(env(), m_lctx, e, f_type, a_type);
}
return instantiate(binding_body(f_type), app_arg(e));
@@ -987,7 +999,7 @@ lbool type_checker::lazy_delta_reduction(expr & t_n, expr & s_n) {
lbool r = is_def_eq_offset(t_n, s_n);
if (r != l_undef) return r;
if (!has_fvar(t_n) && !has_fvar(s_n)) {
if ((!has_fvar(t_n) && !has_fvar(s_n)) || m_eager_reduce) {
if (auto t_v = reduce_nat(t_n)) {
return to_lbool(is_def_eq_core(*t_v, s_n));
} else if (auto s_v = reduce_nat(s_n)) {
@@ -1075,7 +1087,7 @@ bool type_checker::is_def_eq_core(expr const & t, expr const & s) {
// we fully reduce `t` and check whether result is `s`.
// This code path is taken in particular when using the `decide` tactic, which produces
// proof terms of the form `Eq.refl true : decide p = true`.
if (!has_fvar(t) && is_constant(s, *g_bool_true)) {
if ((!has_fvar(t) || m_eager_reduce) && is_constant(s, *g_bool_true)) {
if (is_constant(whnf(t), *g_bool_true)) {
return true;
}
@@ -1204,6 +1216,7 @@ void initialize_type_checker() {
mark_persistent(g_kernel_fresh->raw());
g_bool_true = new name{"Bool", "true"};
mark_persistent(g_bool_true->raw());
g_eager_reduce = new name{"eagerReduce"};
g_dont_care = new_persistent_expr_const("dontcare");
g_nat_zero = new_persistent_expr_const({"Nat", "zero"});
g_nat_succ = new_persistent_expr_const({"Nat", "succ"});
@@ -1230,6 +1243,7 @@ void initialize_type_checker() {
void finalize_type_checker() {
delete g_kernel_fresh;
delete g_bool_true;
delete g_eager_reduce;
delete g_dont_care;
delete g_nat_succ;
delete g_nat_zero;

View File

@@ -46,6 +46,11 @@ private:
diagnostics * m_diag;
local_ctx m_lctx;
definition_safety m_definition_safety;
/*
`m_eager_reduce` is set to true whenever we are type checking an application argument that has been
wrapped with `eagerReduce`.
*/
bool m_eager_reduce = false;
/* When `m_lparams != nullptr, the `check` method makes sure all level parameters
are in `m_lparams`. */
names const * m_lparams;

View File

@@ -0,0 +1,2 @@
example (x: Nat) : UInt32.size - x < UInt64.size := by
grind only

View File

@@ -16,7 +16,8 @@ trace: [grind.debug.proof] Classical.byContradiction fun h =>
let e_2 := Expr.intMul 0 (Expr.var 0);
let p_1 := Poly.nil;
diseq_unsat ctx
(diseq_norm ctx e_2 e_1 p_1 (Eq.refl true) (CommRing.diseq_norm rctx re_1 re_2 rp_1 (Eq.refl true) h))
(diseq_norm ctx e_2 e_1 p_1 (eagerReduce (Eq.refl true))
(CommRing.diseq_norm rctx re_1 re_2 rp_1 (eagerReduce (Eq.refl true)) h))
-/
#guard_msgs in
open Linarith in

View File

@@ -148,7 +148,7 @@ fun x y z =>
(((((((Expr.var 1).add (Expr.mulL 3 (Expr.var 0))).add (Expr.num 1)).add (Expr.num 1)).add (Expr.var 2)).add
(Expr.var 1)).sub
(Expr.var 0))
(Eq.refl true)))
(eagerReduce (Eq.refl true))))
-/
#guard_msgs (info) in
open Int.Linear in
@@ -170,7 +170,7 @@ fun x y z f =>
(((((((Expr.var 0).add (Expr.mulL 3 (Expr.var 1))).add (Expr.num 1)).add (Expr.num 1)).add (Expr.var 2)).add
(Expr.var 0)).sub
(Expr.var 1))
(Eq.refl true)))
(eagerReduce (Eq.refl true))))
(f y))
-/
#guard_msgs (info) in
@@ -295,7 +295,7 @@ fun a b =>
((((Expr.var 1).add ((Expr.num 21).sub (Expr.var 1))).add
(Expr.mulL 3 ((Expr.var 1).add (Expr.mulL 2 (Expr.var 0))))).add
(Expr.num 12))
2 (Poly.add 1 1 (Poly.add 2 0 (Poly.num 11))) 3 (Eq.refl true))))
2 (Poly.add 1 1 (Poly.add 2 0 (Poly.num 11))) 3 (eagerReduce (Eq.refl true)))))
(iff_self (2 a + 2 * b + 11)))
-/
#guard_msgs (info) in
@@ -318,7 +318,7 @@ fun a b =>
((((Expr.var 1).add ((Expr.num 11).sub (Expr.var 1))).add
(Expr.mulL 3 ((Expr.var 1).add (Expr.mulL 2 (Expr.var 0))))).sub
(Expr.num 11))
2 (Poly.add 1 1 (Poly.add 2 0 (Poly.num 0))) 3 (Eq.refl true)))
2 (Poly.add 1 1 (Poly.add 2 0 (Poly.num 0))) 3 (eagerReduce (Eq.refl true))))
Int.dvd_add_self_mul._simp_1))
Int.dvd_add_self_mul._simp_1)
(iff_self (2 a)))