summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Lahfa2024-06-12 13:59:11 +0200
committerRyan Lahfa2024-06-12 14:27:11 +0200
commitf3b22b5cca9bc1154f55a81c9a82dc491074067d (patch)
tree4a3f54ee8e95dbeed37a3f3d78ec0d0ac1de7883
parente60d525fe3dffa035d2a551af624747dca6e1c1e (diff)
backends/lean: introduce `HasIntPred` automation
`HasIntPred` enable generation of facts based on specific terms in the context rather than their types, e.g. if the "length of a list" occurs in the context, generate the fact 0 ≤ length of that list, which can be further used for `scalar_tac` automation to discharge bounds goals. The aim is to use it to simplify various height related computations, e.g. whenever "height of a (left ; right) tree" is encountered, generate "height left < height of a (left ; right) tree", etc. Signed-off-by: Ryan Lahfa <ryan.lahfa@inria.fr>
-rw-r--r--backends/lean/Base/Arith/Int.lean38
-rw-r--r--backends/lean/Base/IList/IList.lean8
2 files changed, 38 insertions, 8 deletions
diff --git a/backends/lean/Base/Arith/Int.lean b/backends/lean/Base/Arith/Int.lean
index 4a3db5f8..a1cb9da3 100644
--- a/backends/lean/Base/Arith/Int.lean
+++ b/backends/lean/Base/Arith/Int.lean
@@ -21,6 +21,11 @@ class HasIntProp (a : Sort u) where
prop_ty : a → Prop
prop : ∀ x:a, prop_ty x
+/- Terms that induces predicates: if we can find the term `x`, we can introduce `concl` in the context. -/
+class HasIntPred {a: Sort u} (x: a) where
+ concl : Prop
+ prop : concl
+
/- Proposition with implications: if we find P we can introduce Q in the context -/
class PropHasImp (x : Prop) where
concl : Prop
@@ -106,12 +111,18 @@ def collectInstancesFromMainCtx (k : Expr → MetaM (Option Expr)) : Tactic.Tact
let hs := HashSet.empty
-- Explore the declarations
let decls ← ctx.getDecls
- let hs ← decls.foldlM (fun hs d => collectInstances k hs d.toExpr) hs
+ let hs ← decls.foldlM (fun hs d => do
+ -- Collect instances over all subexpressions
+ -- of the inferred type rather than the declaration expression
+ -- which is often just a name.
+ let ty ← Lean.Meta.inferType d.toExpr
+ collectInstances k hs ty
+ ) hs
-- Also explore the goal
collectInstances k hs (← Tactic.getMainTarget)
-- Helper
-def lookupProp (fName : String) (className : Name) (e : Expr) : MetaM (Option Expr) := do
+def lookupProp (fName : String) (className : Name) (e : Expr) (instantiateClassFn : Expr → Expr → Array Expr) (instantiateProjectionFn : Expr → Array Expr) : MetaM (Option Expr) := do
trace[Arith] fName
-- TODO: do we need Lean.observing?
-- This actually eliminates the error messages
@@ -119,23 +130,31 @@ def lookupProp (fName : String) (className : Name) (e : Expr) : MetaM (Option Ex
Lean.observing? do
trace[Arith] m!"{fName}: observing: {e}"
let ty ← Lean.Meta.inferType e
- let hasProp ← mkAppM className #[ty]
+ let hasProp ← mkAppM className (instantiateClassFn ty e)
let hasPropInst ← trySynthInstance hasProp
match hasPropInst with
| LOption.some i =>
trace[Arith] "Found {fName} instance"
let i_prop ← mkProjection i (Name.mkSimple "prop")
- some (← mkAppM' i_prop #[e])
+ some (← mkAppM' i_prop (instantiateProjectionFn e))
| _ => none
-- Return an instance of `HasIntProp` for `e` if it has some
def lookupHasIntProp (e : Expr) : MetaM (Option Expr) :=
- lookupProp "lookupHasIntProp" ``HasIntProp e
+ lookupProp "lookupHasIntProp" ``HasIntProp e (fun ty _ => #[ty]) (fun e => #[e])
-- Collect the instances of `HasIntProp` for the subexpressions in the context
def collectHasIntPropInstancesFromMainCtx : Tactic.TacticM (HashSet Expr) := do
collectInstancesFromMainCtx lookupHasIntProp
+-- Return an instance of `HasIntPred` for `e` if it has some
+def lookupHasIntPred (e : Expr) : MetaM (Option Expr) :=
+ lookupProp "lookupHasIntPred" ``HasIntPred e (fun _ term => #[term]) (fun _ => #[])
+
+-- Collect the instances of `HasIntPred` for the subexpressions in the context
+def collectHasIntPredInstancesFromMainCtx : Tactic.TacticM (HashSet Expr) := do
+ collectInstancesFromMainCtx lookupHasIntPred
+
-- Return an instance of `PropHasImp` for `e` if it has some
def lookupPropHasImp (e : Expr) : MetaM (Option Expr) := do
trace[Arith] m!"lookupPropHasImp: {e}"
@@ -193,6 +212,13 @@ def introHasIntPropInstances : Tactic.TacticM (Array Expr) := do
elab "intro_has_int_prop_instances" : tactic => do
let _ ← introHasIntPropInstances
+def introHasIntPredInstances : Tactic.TacticM (Array Expr) := do
+ trace[Arith] "Introducing the HasIntPred instances"
+ introInstances ``HasIntPred.concl lookupHasIntPred
+
+elab "intro_has_int_pred_instances" : tactic => do
+ let _ ← introHasIntPredInstances
+
def introPropHasImpInstances : Tactic.TacticM (Array Expr) := do
trace[Arith] "Introducing the PropHasImp instances"
introInstances ``PropHasImp.concl lookupPropHasImp
@@ -208,6 +234,8 @@ def intTacPreprocess (extraPreprocess : Tactic.TacticM Unit) : Tactic.TacticM U
Tactic.withMainContext do
-- Introduce the instances of `HasIntProp`
let _ ← introHasIntPropInstances
+ -- Introduce the instances of `HasIntPred`
+ let _ ← introHasIntPredInstances
-- Introduce the instances of `PropHasImp`
let _ ← introPropHasImpInstances
-- Extra preprocessing
diff --git a/backends/lean/Base/IList/IList.lean b/backends/lean/Base/IList/IList.lean
index ca5ee266..9fe2297f 100644
--- a/backends/lean/Base/IList/IList.lean
+++ b/backends/lean/Base/IList/IList.lean
@@ -19,9 +19,11 @@ theorem len_pos : 0 ≤ (ls : List α).len := by
induction ls <;> simp [*]
linarith
-instance (a : Type u) : Arith.HasIntProp (List a) where
- prop_ty := λ ls => 0 ≤ ls.len
- prop := λ ls => ls.len_pos
+instance (l: List a) : Arith.HasIntPred (l.len) where
+ concl := 0 ≤ l.len
+ prop := l.len_pos
+
+example (l: List a): 0 ≤ l.len := by scalar_tac
-- Remark: if i < 0, then the result is none
def indexOpt (ls : List α) (i : Int) : Option α :=