Compare commits

...

11 Commits

Author SHA1 Message Date
Leonardo de Moura
105be27213 feat: multi-pattern support in the ematch procedure 2024-12-30 18:26:29 -08:00
Leonardo de Moura
b05d2fbd32 fix: avoid redundant search space 2024-12-30 18:19:35 -08:00
Leonardo de Moura
4a1c15dcb3 doc: EMatch.lean 2024-12-30 17:50:55 -08:00
Leonardo de Moura
fc89c0aa39 chore: fix test 2024-12-30 17:21:38 -08:00
Leonardo de Moura
a527e3e9b9 fix: do not include proofs in ematching patterns 2024-12-30 17:19:01 -08:00
Leonardo de Moura
8dbbcf2652 test: ematch 2024-12-30 17:14:04 -08:00
Leonardo de Moura
ba9f62f5e3 chore: add grind.ematch.pattern trace option 2024-12-30 16:46:28 -08:00
Leonardo de Moura
8fd06703e2 feat: add ematch to grind 2024-12-30 16:37:55 -08:00
Leonardo de Moura
32e96a07f3 chore: move trace[grind.eqc] to reduce noise 2024-12-30 12:53:50 -08:00
Leonardo de Moura
72514e259c feat: add isCongrRoot 2024-12-30 12:53:43 -08:00
Leonardo de Moura
8ce099fe05 chore: cleanup grind trace options 2024-12-30 11:41:40 -08:00
15 changed files with 404 additions and 78 deletions

View File

@@ -25,18 +25,23 @@ import Lean.Meta.Tactic.Grind.EMatchTheorem
namespace Lean
/-! Trace options for `grind` users -/
builtin_initialize registerTraceClass `grind
builtin_initialize registerTraceClass `grind.eq
builtin_initialize registerTraceClass `grind.assert
builtin_initialize registerTraceClass `grind.eqc
builtin_initialize registerTraceClass `grind.internalize
builtin_initialize registerTraceClass `grind.ematch
builtin_initialize registerTraceClass `grind.ematch.pattern
builtin_initialize registerTraceClass `grind.ematch.instance
builtin_initialize registerTraceClass `grind.issues
builtin_initialize registerTraceClass `grind.add
builtin_initialize registerTraceClass `grind.pre
builtin_initialize registerTraceClass `grind.simp
/-! Trace options for `grind` developers -/
builtin_initialize registerTraceClass `grind.debug
builtin_initialize registerTraceClass `grind.debug.proofs
builtin_initialize registerTraceClass `grind.simp
builtin_initialize registerTraceClass `grind.congr
builtin_initialize registerTraceClass `grind.proof
builtin_initialize registerTraceClass `grind.proof.detail
builtin_initialize registerTraceClass `grind.pattern
builtin_initialize registerTraceClass `grind.internalize
builtin_initialize registerTraceClass `grind.debug.congr
builtin_initialize registerTraceClass `grind.debug.pre
builtin_initialize registerTraceClass `grind.debug.proof
builtin_initialize registerTraceClass `grind.debug.proj
end Lean

View File

@@ -82,13 +82,13 @@ private partial def updateMT (root : Expr) : GoalM Unit := do
updateMT parent
private partial def addEqStep (lhs rhs proof : Expr) (isHEq : Bool) : GoalM Unit := do
trace[grind.eq] "{lhs} {if isHEq then "" else "="} {rhs}"
let lhsNode getENode lhs
let rhsNode getENode rhs
if isSameExpr lhsNode.root rhsNode.root then
-- `lhs` and `rhs` are already in the same equivalence class.
trace[grind.debug] "{← ppENodeRef lhs} and {← ppENodeRef rhs} are already in the same equivalence class"
return ()
trace[grind.eqc] "{lhs} {if isHEq then "" else "="} {rhs}"
let lhsRoot getENode lhsNode.root
let rhsRoot getENode rhsNode.root
let mut valueInconsistency := false
@@ -195,7 +195,7 @@ def addHEq (lhs rhs proof : Expr) : GoalM Unit := do
Adds a new `fact` justified by the given proof and using the given generation.
-/
def add (fact : Expr) (proof : Expr) (generation := 0) : GoalM Unit := do
trace[grind.add] "{proof} : {fact}"
trace[grind.assert] "{fact}"
if ( isInconsistent) then return ()
resetNewEqs
let_expr Not p := fact
@@ -203,7 +203,6 @@ def add (fact : Expr) (proof : Expr) (generation := 0) : GoalM Unit := do
go p true
where
go (p : Expr) (isNeg : Bool) : GoalM Unit := do
trace[grind.add] "isNeg: {isNeg}, {p}"
match_expr p with
| Eq _ lhs rhs => goEq p lhs rhs isNeg false
| HEq _ lhs _ rhs => goEq p lhs rhs isNeg true

View File

@@ -0,0 +1,241 @@
/-
Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Lean.Meta.Tactic.Grind.Types
import Lean.Meta.Tactic.Grind.Internalize
namespace Lean.Meta.Grind
/-- Returns maximum term generation that is considered during ematching -/
private def getMaxGeneration : GoalM Nat := do
return 10000 -- TODO
/-- Returns `true` if the maximum number of instances has been reached. -/
private def checkMaxInstancesExceeded : GoalM Bool := do
return false -- TODO
namespace EMatch
/-! This module implements a simple E-matching procedure as a backtracking search. -/
/-- We represent an `E-matching` problem as a list of constraints. -/
inductive Cnstr where
| /-- Matches pattern `pat` with term `e` -/
«match» (pat : Expr) (e : Expr)
| /-- This constraint is used to encode multi-patterns. -/
«continue» (pat : Expr)
deriving Inhabited
/--
Internal "marker" for representing unassigned elemens in the `assignment` field.
This is a small hack to avoid one extra level of indirection by using `Option Expr` at `assignment`.
-/
private def unassigned : Expr := mkConst (Name.mkSimple "[grind_unassigned]")
private def assignmentToMessageData (assignment : Array Expr) : Array MessageData :=
assignment.reverse.map fun e =>
if isSameExpr e unassigned then m!"_" else m!"{e}"
/--
Choice point for the backtracking search.
The state of the procedure contains a stack of choices.
-/
structure Choice where
/-- Contraints to be processed. -/
cnstrs : List Cnstr
/-- Maximum term generation found so far. -/
gen : Nat
/-- Partial assignment so far. Recall that pattern variables are encoded as de-Bruijn variables. -/
assignment : Array Expr
deriving Inhabited
/-- Theorem instances found so far. We only internalize them after we complete a full round of E-matching. -/
structure TheoremInstance where
prop : Expr
proof : Expr
generation : Nat
deriving Inhabited
/-- Context for the E-matching monad. -/
structure Context where
/-- `useMT` is `true` if we are using the mod-time optimization. It is always set to false for new `EMatchTheorem`s. -/
useMT : Bool := true
/-- `EMatchTheorem` being processed. -/
thm : EMatchTheorem := default
deriving Inhabited
/-- State for the E-matching monad -/
structure State where
/-- Choices that still have to be processed. -/
choiceStack : List Choice := []
newInstances : PArray TheoremInstance := {}
deriving Inhabited
abbrev M := ReaderT Context $ StateRefT State GoalM
def M.run' (x : M α) : GoalM α :=
x {} |>.run' {}
/--
Assigns `bidx := e` in `c`. If `bidx` is already assigned in `c`, we check whether
`e` and `c.assignment[bidx]` are in the same equivalence class.
This function assumes `bidx < c.assignment.size`.
Recall that we initialize the assignment array with the number of theorem parameters.
-/
private def assign? (c : Choice) (bidx : Nat) (e : Expr) : OptionT GoalM Choice := do
if h : bidx < c.assignment.size then
let v := c.assignment[bidx]
if isSameExpr v unassigned then
return { c with assignment := c.assignment.set bidx e }
else
guard ( isEqv v e)
return c
else
-- `Choice` was not properly initialized
unreachable!
/--
Returns `true` if the function `pFn` of a pattern is equivalent to the function `eFn`.
Recall that we ignore universe levels in patterns.
-/
private def eqvFunctions (pFn eFn : Expr) : Bool :=
(pFn.isFVar && pFn == eFn)
|| (pFn.isConst && eFn.isConstOf pFn.constName!)
/--
Matches arguments of pattern `p` with term `e`. Returns `some` if successful,
and `none` otherwise. It may update `c`s assignment and list of contraints to be
processed.
-/
private partial def matchArgs? (c : Choice) (p : Expr) (e : Expr) : OptionT GoalM Choice := do
if !p.isApp then return c -- Done
let pArg := p.appArg!
let eArg := e.appArg!
let goFn c := matchArgs? c p.appFn! e.appFn!
if isPatternDontCare pArg then
goFn c
else if pArg.isBVar then
goFn ( assign? c pArg.bvarIdx! eArg)
else if let some pArg := groundPattern? pArg then
guard ( isEqv pArg eArg)
goFn c
else
goFn { c with cnstrs := .match pArg eArg :: c.cnstrs }
/--
Matches pattern `p` with term `e` with respect to choice `c`.
We traverse the equivalence class of `e` looking for applications compatible with `p`.
For each candidate application, we match the arguments and may update `c`s assignments and contraints.
We add the updated choices to the choice stack.
-/
private partial def processMatch (c : Choice) (p : Expr) (e : Expr) : M Unit := do
let maxGeneration getMaxGeneration
let pFn := p.getAppFn
let numArgs := p.getAppNumArgs
let mut curr := e
repeat
let n getENode curr
if n.generation <= maxGeneration
-- uses heterogeneous equality or is the root of its congruence class
&& (n.heqProofs || isSameExpr curr n.cgRoot)
&& eqvFunctions pFn curr.getAppFn
&& curr.getAppNumArgs == numArgs then
if let some c matchArgs? c p curr |>.run then
let gen := n.generation
let c := { c with gen := Nat.max gen c.gen }
modify fun s => { s with choiceStack := c :: s.choiceStack }
curr getNext curr
if isSameExpr curr e then break
/-- Processes `continue` contraint used to implement multi-patterns. -/
private def processContinue (c : Choice) (p : Expr) : M Unit := do
let some apps := ( getThe Goal).appMap.find? p.toHeadIndex
| return ()
let maxGeneration getMaxGeneration
for app in apps do
let n getENode app
if n.generation <= maxGeneration
&& (n.heqProofs || isSameExpr n.cgRoot app) then
if let some c matchArgs? c p app |>.run then
let gen := n.generation
let c := { c with gen := Nat.max gen c.gen }
modify fun s => { s with choiceStack := c :: s.choiceStack }
private partial def instantiateTheorem (c : Choice) : M Unit := do
trace[grind.ematch.instance] "{(← read).thm.origin.key} : {assignmentToMessageData c.assignment}"
-- TODO
return ()
/-- Process choice stack until we don't have more choices to be processed. -/
private partial def processChoices : M Unit := do
unless ( get).choiceStack.isEmpty do
let c modifyGet fun s : State => (s.choiceStack.head!, { s with choiceStack := s.choiceStack.tail! })
match c.cnstrs with
| [] => instantiateTheorem c
| .match p e :: cnstrs => processMatch { c with cnstrs } p e
| .continue p :: cnstrs => processContinue { c with cnstrs } p
processChoices
private def main (p : Expr) (cnstrs : List Cnstr) : M Unit := do
let some apps := ( getThe Goal).appMap.find? p.toHeadIndex
| return ()
let numParams := ( read).thm.numParams
let assignment := mkArray numParams unassigned
let useMT := ( read).useMT
let gmt := ( getThe Goal).gmt
for app in apps do
let n getENode app
if (n.heqProofs || isSameExpr n.cgRoot app) &&
(!useMT || n.mt == gmt) then
if let some c matchArgs? { cnstrs, assignment, gen := n.generation } p app |>.run then
modify fun s => { s with choiceStack := [c] }
processChoices
def ematchTheorem (thm : EMatchTheorem) : M Unit := do
withReader (fun ctx => { ctx with thm }) do
let ps := thm.patterns
match ps, ( read).useMT with
| [p], _ => main p []
| p::ps, false => main p (ps.map (.continue ·))
| _::_, true => tryAll ps []
| _, _ => unreachable!
where
/--
When using the mod-time optimization with multi-patterns,
we must start ematching at each different pattern. That is,
if we have `[p₁, p₂, p₃]`, we must execute
- `main p₁ [.continue p₂, .continue p₃]`
- `main p₂ [.continue p₁, .continue p₃]`
- `main p₃ [.continue p₁, .continue p₂]`
-/
tryAll (ps : List Expr) (cs : List Cnstr) : M Unit := do
match ps with
| [] => return ()
| p::ps =>
main p (cs.reverse ++ (ps.map (.continue ·)))
tryAll ps (.continue p :: cs)
def ematchTheorems (thms : PArray EMatchTheorem) : M Unit := do
thms.forM ematchTheorem
def internalizeNewInstances : M Unit := do
-- TODO
return ()
end EMatch
open EMatch
/-- Performs one round of E-matching, and internalizes new instances. -/
def ematch : GoalM Unit := do
let go (thms newThms : PArray EMatchTheorem) : EMatch.M Unit := do
withReader (fun ctx => { ctx with useMT := true }) <| ematchTheorems thms
withReader (fun ctx => { ctx with useMT := false }) <| ematchTheorems newThms
internalizeNewInstances
unless ( checkMaxInstancesExceeded) do
go ( get).thms ( get).newThms |>.run'
modify fun s => { s with thms := s.thms ++ s.newThms, newThms := {}, gmt := s.gmt + 1 }
end Lean.Meta.Grind

View File

@@ -125,15 +125,21 @@ private def getPatternFn? (pattern : Expr) : Option Expr :=
| f@(.fvar _) => some f
| _ => none
private structure PatternFunInfo where
instImplicitMask : Array Bool
typeMask : Array Bool
/--
Returns a bit-mask `mask` s.t. `mask[i]` is true if the the corresponding argument is
- a type or type former, or
- a proof, or
- an instance implicit argument
private def getPatternFunInfo (f : Expr) (numArgs : Nat) : MetaM PatternFunInfo := do
When `mask[i]`, we say the corresponding argument is a "support" argument.
-/
private def getPatternFunMask (f : Expr) (numArgs : Nat) : MetaM (Array Bool) := do
forallBoundedTelescope ( inferType f) numArgs fun xs _ => do
let typeMask xs.mapM fun x => isTypeFormer x
let instImplicitMask xs.mapM fun x => return ( x.fvarId!.getDecl).binderInfo matches .instImplicit
return { typeMask, instImplicitMask }
xs.mapM fun x => do
if ( isTypeFormer x <||> isProof x) then
return true
else
return ( x.fvarId!.getDecl).binderInfo matches .instImplicit
private partial def go (pattern : Expr) (root := false) : M Expr := do
if root && !pattern.hasLooseBVars then
@@ -143,11 +149,10 @@ private partial def go (pattern : Expr) (root := false) : M Expr := do
assert! f.isConst || f.isFVar
saveSymbol f.toHeadIndex
let mut args := pattern.getAppArgs
let { instImplicitMask, typeMask } getPatternFunInfo f args.size
let supportMask getPatternFunMask f args.size
for i in [:args.size] do
let arg := args[i]!
let isType := typeMask[i]?.getD false
let isInstImplicit := instImplicitMask[i]?.getD false
let isSupport := supportMask[i]?.getD false
let arg if !arg.hasLooseBVars then
if arg.hasMVar then
pure dontCare
@@ -155,13 +160,13 @@ private partial def go (pattern : Expr) (root := false) : M Expr := do
pure <| mkGroundPattern arg
else match arg with
| .bvar idx =>
if (isType || isInstImplicit) && ( foundBVar idx) then
if isSupport && ( foundBVar idx) then
pure dontCare
else
saveBVar idx
pure arg
| _ =>
if isType || isInstImplicit then
if isSupport then
pure dontCare
else if let some _ := getPatternFn? arg then
go arg
@@ -305,7 +310,7 @@ def addEMatchTheorem (declName : Name) (numParams : Nat) (patterns : List Expr)
let proof := mkConst declName us
let (patterns, symbols, bvarFound) NormalizePattern.main patterns
assert! symbols.all fun s => s matches .const _
trace[grind.pattern] "{declName}: {patterns.map ppPattern}"
trace[grind.ematch.pattern] "{declName}: {patterns.map ppPattern}"
if let .missing pos checkCoverage proof numParams bvarFound then
let pats : MessageData := m!"{patterns.map ppPattern}"
throwError "invalid pattern(s) for `{declName}`{indentD pats}\nthe following theorem parameters cannot be instantiated:{indentD (← ppParamsAt proof numParams pos)}"

View File

@@ -22,7 +22,7 @@ def addCongrTable (e : Expr) : GoalM Unit := 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'}"
trace[grind.debug.congr] "{e} = {e'}"
pushEqHEq e e' congrPlaceholderProof
let node getENode e
setENode e { node with cgRoot := e' }
@@ -59,11 +59,11 @@ private partial def activateTheoremPatterns (fName : Name) (generation : Nat) :
let thm := { thm with symbols }
match symbols with
| [] =>
trace[grind.pattern] "activated `{thm.origin.key}`"
let thm := { thm with patterns := ( thm.patterns.mapM (internalizePattern · generation)) }
trace[grind.ematch] "activated `{thm.origin.key}`, {thm.patterns.map ppPattern}"
modify fun s => { s with newThms := s.newThms.push thm }
| _ =>
trace[grind.pattern] "reinsert `{thm.origin.key}`"
trace[grind.ematch] "reinsert `{thm.origin.key}`"
modify fun s => { s with thmMap := s.thmMap.insert thm }
partial def internalize (e : Expr) (generation : Nat) : GoalM Unit := do

View File

@@ -18,6 +18,7 @@ import Lean.Meta.Tactic.Grind.Injection
import Lean.Meta.Tactic.Grind.Core
import Lean.Meta.Tactic.Grind.Simp
import Lean.Meta.Tactic.Grind.Run
import Lean.Meta.Tactic.Grind.EMatch
namespace Lean.Meta.Grind
namespace Preprocessor
@@ -122,13 +123,14 @@ partial def loop (goal : Goal) : PreM Unit := do
else
loop goal
def ppGoals : PreM Format := do
def ppGoals (goals : PArray Goal) : PreM Format := do
let mut r := f!""
for goal in ( get).goals do
for goal in goals do
let (f, _) GoalM.run goal ppState
r := r ++ Format.line ++ f
return r
-- TODO: refactor this code
def preprocess (mvarId : MVarId) : PreM State := do
mvarId.ensureProp
-- TODO: abstract metavars
@@ -140,9 +142,12 @@ def preprocess (mvarId : MVarId) : PreM State := do
let mvarId mvarId.unfoldReducible
let mvarId mvarId.betaReduce
loop ( mkGoal mvarId)
let goals := ( get).goals
-- Testing `ematch` module here. We will rewrite this part later.
let goals goals.mapM fun goal => GoalM.run' goal ematch
if ( isTracingEnabledFor `grind.pre) then
trace[grind.pre] ( ppGoals)
for goal in ( get).goals do
trace[grind.debug.pre] ( ppGoals goals)
for goal in goals do
discard <| GoalM.run' goal <| checkInvariants (expensive := true)
get

View File

@@ -19,17 +19,21 @@ def propagateProjEq (parent : Expr) : GoalM Unit := do
let .const declName _ := parent.getAppFn | return ()
let some info getProjectionFnInfo? declName | return ()
unless info.numParams + 1 == parent.getAppNumArgs do return ()
-- It is wasteful to add equation if `parent` is not the root of its congruence class
unless ( isCongrRoot parent) do return ()
let arg := parent.appArg!
let ctor getRoot arg
unless ctor.isAppOf info.ctorName do return ()
if isSameExpr arg ctor then
let idx := info.numParams + info.i
unless idx < ctor.getAppNumArgs do return ()
let v := ctor.getArg! idx
pushEq parent v ( mkEqRefl v)
let parentNew if isSameExpr arg ctor then
pure parent
else
let newProj := mkApp parent.appFn! ctor
let newProj shareCommon newProj
internalize newProj ( getGeneration parent)
let parentNew shareCommon (mkApp parent.appFn! ctor)
internalize parentNew ( getGeneration parent)
pure parentNew
trace[grind.debug.proj] "{parentNew}"
let idx := info.numParams + info.i
unless idx < ctor.getAppNumArgs do return ()
let v := ctor.getArg! idx
pushEq parentNew v ( mkEqRefl v)
end Lean.Meta.Grind

View File

@@ -217,20 +217,20 @@ It assumes `a` and `b` are in the same equivalence class.
@[export lean_grind_mk_eq_proof]
def mkEqProofImpl (a b : Expr) : GoalM Expr := do
let p go
trace[grind.proof.detail] "{p}"
trace[grind.debug.proof] "{p}"
return p
where
go : GoalM Expr := do
let n getRootENode a
if !n.heqProofs then
trace[grind.proof] "{a} = {b}"
trace[grind.debug.proof] "{a} = {b}"
mkEqProofCore a b (heq := false)
else
if ( hasSameType a b) then
trace[grind.proof] "{a} = {b}"
trace[grind.debug.proof] "{a} = {b}"
mkEqOfHEq ( mkEqProofCore a b (heq := true))
else
trace[grind.proof] "{a} ≡ {b}"
trace[grind.debug.proof] "{a} ≡ {b}"
mkEqProofCore a b (heq := true)
def mkHEqProof (a b : Expr) : GoalM Expr :=

View File

@@ -283,6 +283,8 @@ structure Goal where
Local theorem provided by users are added directly into `newThms`.
-/
thmMap : EMatchTheorems
/-- Number of theorem instances generated so far -/
numInstances : Nat := 0
deriving Inhabited
def Goal.admit (goal : Goal) : MetaM Unit :=
@@ -465,6 +467,10 @@ def mkENode (e : Expr) (generation : Nat) : GoalM Unit := do
let interpreted isInterpreted e
mkENodeCore e interpreted ctor generation
/-- Returns `true` is `e` is the root of its congruence class. -/
def isCongrRoot (e : Expr) : GoalM Bool := do
return isSameExpr e ( getENode e).cgRoot
/-- Return `true` if the goal is inconsistent. -/
def isInconsistent : GoalM Bool :=
return ( get).inconsistent

View File

@@ -67,18 +67,15 @@ end Ex2
example (f g : (α : Type) α α) (a : α) (b : β) : (h₁ : α = β) (h₂ : HEq a b) (h₃ : f = g) HEq (f α a) (g β b) := by
grind
set_option trace.grind.proof true in
set_option trace.grind.proof.detail true in
set_option trace.grind.debug.proof true in
example (f : {α : Type} α Nat Bool Nat) (a b : Nat) : f a 0 true = v₁ f b 0 true = v₂ a = b v₁ = v₂ := by
grind
set_option trace.grind.proof true in
set_option trace.grind.proof.detail true in
set_option trace.grind.debug.proof true in
example (f : {α : Type} α Nat Bool Nat) (a b : Nat) : f a b x = v₁ f a b y = v₂ x = y v₁ = v₂ := by
grind
set_option trace.grind.proof true in
set_option trace.grind.proof.detail true in
set_option trace.grind.debug.proof true in
theorem ex1 (f : {α : Type} α Nat Bool Nat) (a b c : Nat) : f a b x = v₁ f c b y = v₂ a = c x = y v₁ = v₂ := by
grind

View File

@@ -0,0 +1,52 @@
set_option trace.grind.ematch.pattern true
grind_pattern Array.get_set_eq => a.set i v h
grind_pattern Array.get_set_ne => (a.set i v hi)[j]
-- Trace instances of the theorems above found using ematching
set_option trace.grind.ematch.instance true
/--
info: [grind.ematch.instance] Array.get_set_eq : [α, bs, j, w, Lean.Grind.nestedProof (j < bs.toList.length) h₂]
[grind.ematch.instance] Array.get_set_eq : [α, as, i, v, Lean.Grind.nestedProof (i < as.toList.length) h₁]
[grind.ematch.instance] Array.get_set_ne : [α, bs, j, Lean.Grind.nestedProof (j < bs.toList.length) h₂, i, w, _, _]
-/
#guard_msgs (info) in
example (as : Array α)
(i : Nat)
(h₁ : i < as.size)
(h₂ : bs = as.set i v)
(_ : ds = bs)
(h₂ : j < bs.size)
(h₃ : cs = bs.set j w)
(h₄ : i j)
(h₅ : i < cs.size)
: p (cs[i] = as[i]) := by
fail_if_success grind
sorry
opaque R : Nat Nat Prop
theorem Rtrans (a b c : Nat) : R a b R b c R a c := sorry
grind_pattern Rtrans => R a b, R b c
/--
info: [grind.ematch.instance] Rtrans : [b, c, d, _, _]
[grind.ematch.instance] Rtrans : [a, b, c, _, _]
-/
#guard_msgs (info) in
example : R a b R b c R c d False := by
fail_if_success grind
sorry
-- In the following test we are performing one round of ematching only
/--
info: [grind.ematch.instance] Rtrans : [c, d, e, _, _]
[grind.ematch.instance] Rtrans : [c, d, n, _, _]
[grind.ematch.instance] Rtrans : [b, c, d, _, _]
[grind.ematch.instance] Rtrans : [a, b, c, _, _]
-/
#guard_msgs (info) in
example : R a b R b c R c d R d e R d n False := by
fail_if_success grind
sorry

View File

@@ -1,20 +1,18 @@
set_option trace.grind.pattern true
set_option trace.grind.ematch.pattern true
/--
info: [grind.pattern] Array.getElem_push_lt: [@getElem ? `[Nat] #4 ? ? (@Array.push ? #3 #2) #1 ?]
info: [grind.ematch.pattern] Array.getElem_push_lt: [@getElem ? `[Nat] #4 ? ? (@Array.push ? #3 #2) #1 ?]
-/
#guard_msgs in
grind_pattern Array.getElem_push_lt => (a.push x)[i]
/--
info: [grind.pattern] List.getElem_attach: [@getElem ? `[Nat] ? ? ? (@List.attach #3 #2) #1 ?]
-/
/-- info: [grind.ematch.pattern] List.getElem_attach: [@getElem ? `[Nat] ? ? ? (@List.attach #3 #2) #1 ?] -/
#guard_msgs in
grind_pattern List.getElem_attach => xs.attach[i]
/--
info: [grind.pattern] List.mem_concat_self: [@Membership.mem #2 ? ? (@HAppend.hAppend ? ? ? ? #1 (@List.cons ? #0 (@List.nil ?))) #0]
info: [grind.ematch.pattern] List.mem_concat_self: [@Membership.mem #2 ? ? (@HAppend.hAppend ? ? ? ? #1 (@List.cons ? #0 (@List.nil ?))) #0]
-/
#guard_msgs in
grind_pattern List.mem_concat_self => a xs ++ [a]
@@ -34,7 +32,7 @@ the following theorem parameters cannot be instantiated:
i : Nat
h : i < a.size
---
info: [grind.pattern] Array.getElem_push_lt: [@Array.push #4 #3 #2]
info: [grind.ematch.pattern] Array.getElem_push_lt: [@Array.push #4 #3 #2]
-/
#guard_msgs in
grind_pattern Array.getElem_push_lt => (a.push x)
@@ -56,13 +54,13 @@ instance [Boo α β] : Boo (List α) (Array β) where
theorem fEq [Foo α β] [Boo α β] (a : List α) : (f a).1 = a := rfl
/-- info: [grind.pattern] fEq: [@f ? ? ? ? #0] -/
/-- info: [grind.ematch.pattern] fEq: [@f ? ? ? ? #0] -/
#guard_msgs in
grind_pattern fEq => f a
theorem fEq2 [Foo α β] [Boo α β] (a : List α) (_h : a.length > 5) : (f a).1 = a := rfl
/-- info: [grind.pattern] fEq2: [@f ? ? ? ? #1] -/
/-- info: [grind.ematch.pattern] fEq2: [@f ? ? ? ? #1] -/
#guard_msgs in
grind_pattern fEq2 => f a
@@ -78,7 +76,7 @@ the following theorem parameters cannot be instantiated:
β : Type
inst✝ : Boo α β
---
info: [grind.pattern] gEq: [@g ? ? ? #0]
info: [grind.ematch.pattern] gEq: [@g ? ? ? #0]
-/
#guard_msgs in
grind_pattern gEq => g a
@@ -94,7 +92,7 @@ error: invalid pattern(s) for `hThm1`
the following theorem parameters cannot be instantiated:
c : Nat
---
info: [grind.pattern] hThm1: [plus #2 #3]
info: [grind.ematch.pattern] hThm1: [plus #2 #3]
-/
#guard_msgs in
grind_pattern hThm1 => plus a b
@@ -106,11 +104,11 @@ the following theorem parameters cannot be instantiated:
b : Nat
h : b > 10
---
info: [grind.pattern] hThm1: [plus #2 #1]
info: [grind.ematch.pattern] hThm1: [plus #2 #1]
-/
#guard_msgs in
grind_pattern hThm1 => plus a c
/-- info: [grind.pattern] hThm1: [plus #2 #1, plus #2 #3] -/
/-- info: [grind.ematch.pattern] hThm1: [plus #2 #1, plus #2 #3] -/
#guard_msgs in
grind_pattern hThm1 => plus a c, plus a b

View File

@@ -13,12 +13,13 @@ grind_pattern contains_insert => contains (insertElem s a) a
-- TheoremPattern activation test
set_option trace.grind.pattern true
set_option trace.grind.ematch true
set_option trace.grind.ematch.pattern true
/--
warning: declaration uses 'sorry'
---
info: [grind.pattern] activated `contains_insert`
info: [grind.ematch] activated `contains_insert`, [@contains #3 (@insertElem ? #2 #1 #0) #0]
-/
#guard_msgs in
example [DecidableEq α] (s₁ s₂ : Set α) (a₁ a₂ : α) :
@@ -29,8 +30,8 @@ example [DecidableEq α] (s₁ s₂ : Set α) (a₁ a₂ : α) :
/--
warning: declaration uses 'sorry'
---
info: [grind.pattern] reinsert `contains_insert`
[grind.pattern] activated `contains_insert`
info: [grind.ematch] reinsert `contains_insert`
[grind.ematch] activated `contains_insert`, [@contains #3 (@insertElem ? #2 #1 #0) #0]
-/
#guard_msgs in
example [DecidableEq α] (s₁ s₂ : Set α) (a₁ a₂ : α) :
@@ -44,9 +45,7 @@ def foo (x : List Nat) (y : List Nat) := x ++ y ++ x
theorem fooThm : foo x [a, b] = x ++ [a, b] ++ x := rfl
/--
info: [grind.pattern] fooThm: [foo #0 `[[a, b]]]
-/
/-- info: [grind.ematch.pattern] fooThm: [foo #0 `[[a, b]]] -/
#guard_msgs in
grind_pattern fooThm => foo x [a, b]
@@ -55,13 +54,13 @@ grind_pattern fooThm => foo x [a, b]
warning: declaration uses 'sorry'
---
info: [grind.internalize] foo x y
[grind.pattern] activated `fooThm`
[grind.internalize] [a, b]
[grind.internalize] Nat
[grind.internalize] a
[grind.internalize] [b]
[grind.internalize] b
[grind.internalize] []
[grind.ematch] activated `fooThm`, [foo #0 `[[a, b]]]
[grind.internalize] x
[grind.internalize] y
[grind.internalize] z
@@ -71,3 +70,12 @@ set_option trace.grind.internalize true in
example : foo x y = z False := by
fail_if_success grind
sorry
theorem arrEx [Add α] (as : Array α) (h₁ : i < as.size) (h₂ : i = j) : as[i]+as[j] = as[i] + as[i] := by sorry
/--
info: [grind.ematch.pattern] arrEx: [@HAdd.hAdd #6 ? ? ? (@getElem ? `[Nat] ? ? ? #2 #5 ?) (@getElem ? `[Nat] ? ? ? #2 #4 ?)]
-/
#guard_msgs in
grind_pattern arrEx => as[i]+as[j]'(h₂h₁)

View File

@@ -74,13 +74,12 @@ theorem ex3 (h : a₁ :: { x := a₂, y := a₃ : Point } :: as = b₁ :: { x :=
def h (a : α) := a
set_option trace.grind.pre true in
set_option trace.grind.debug.pre true in
example (p : Prop) (a b c : Nat) : p a = 0 a = b h a = h c a = c c = a a = b b = a a = c := by
grind
set_option trace.grind.proof.detail true
set_option trace.grind.proof true
set_option trace.grind.pre true
set_option trace.grind.debug.proof true
set_option trace.grind.debug.pre true
/--
error: `grind` failed
α : Type
@@ -112,9 +111,8 @@ info: [grind.issues] found congruence between
-/
#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
set_option trace.grind.debug.proof false in
set_option trace.grind.debug.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

View File

@@ -75,3 +75,11 @@ example (a b c : Nat) (f : Nat → Nat) : p = { a := f b, c, b := 4 : Boo Nat }
example (a b c : Nat) (f : Nat Nat) : p.1 f a p = { a := f b, c, b := 4 : Boo Nat } f b = f c a = c False := by
grind
/--
info: [grind.debug.proj] { a := b, b := v₁, c := v₂ }.a
-/
#guard_msgs (info) in
set_option trace.grind.debug.proj true in
example (a b d e : Nat) (x y z : Boo Nat) (f : Nat Boo Nat) : (f d).1 a f d = b, v₁, v₂ x.1 = e y.1 = e z.1 = e f d = x f d = y f d = z b = a False := by
grind