161 lines
7.3 KiB
Text
161 lines
7.3 KiB
Text
/-
|
||
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Leonardo de Moura
|
||
-/
|
||
prelude
|
||
import init.meta.smt.congruence_closure
|
||
import init.meta.attribute init.meta.simp_tactic
|
||
open tactic
|
||
|
||
/- Heuristic instantiation lemma -/
|
||
meta constant hinst_lemma : Type
|
||
|
||
meta constant hinst_lemmas : Type
|
||
|
||
/- (mk_core m e as_simp), m is used to decide which definitions will be unfolded in patterns.
|
||
If as_simp is tt, then this tactic will try to use the left-hand-side of the conclusion
|
||
as a pattern. -/
|
||
meta constant hinst_lemma.mk_core : transparency → expr → bool → tactic hinst_lemma
|
||
meta constant hinst_lemma.mk_from_decl_core : transparency → name → bool → tactic hinst_lemma
|
||
meta constant hinst_lemma.pp : hinst_lemma → tactic format
|
||
meta constant hinst_lemma.id : hinst_lemma → name
|
||
|
||
meta instance : has_to_tactic_format hinst_lemma :=
|
||
⟨hinst_lemma.pp⟩
|
||
|
||
meta def hinst_lemma.mk (h : expr) : tactic hinst_lemma :=
|
||
hinst_lemma.mk_core reducible h ff
|
||
|
||
meta def hinst_lemma.mk_from_decl (h : name) : tactic hinst_lemma :=
|
||
hinst_lemma.mk_from_decl_core reducible h ff
|
||
|
||
meta constant hinst_lemmas.mk : hinst_lemmas
|
||
meta constant hinst_lemmas.add : hinst_lemmas → hinst_lemma → hinst_lemmas
|
||
meta constant hinst_lemmas.fold {α : Type} : hinst_lemmas → α → (hinst_lemma → α → α) → α
|
||
meta constant hinst_lemmas.merge : hinst_lemmas → hinst_lemmas → hinst_lemmas
|
||
|
||
meta def mk_hinst_singleton : hinst_lemma → hinst_lemmas :=
|
||
hinst_lemmas.add hinst_lemmas.mk
|
||
|
||
meta def hinst_lemmas.pp (s : hinst_lemmas) : tactic format :=
|
||
let tac := s^.fold (return format.nil)
|
||
(λ h tac, do
|
||
hpp ← h^.pp,
|
||
r ← tac,
|
||
if r^.is_nil then return hpp
|
||
else return (r ++ to_fmt "," ++ format.line ++ hpp))
|
||
in do
|
||
r ← tac,
|
||
return $ format.cbrace (format.group r)
|
||
|
||
meta instance : has_to_tactic_format hinst_lemmas :=
|
||
⟨hinst_lemmas.pp⟩
|
||
|
||
open tactic
|
||
|
||
private meta def add_lemma (m : transparency) (ignore_errors : bool) (as_simp : bool) (h : name) (hs : hinst_lemmas) : tactic hinst_lemmas :=
|
||
if ignore_errors then (do h ← hinst_lemma.mk_from_decl_core m h as_simp, return $ hs^.add h) <|> return hs
|
||
else (do h ← hinst_lemma.mk_from_decl_core m h as_simp, return $ hs^.add h)
|
||
|
||
meta def to_hinst_lemmas_core (m : transparency) (ignore_errors : bool) : bool → list name → hinst_lemmas → tactic hinst_lemmas
|
||
| as_simp [] hs := return hs
|
||
| as_simp (n::ns) hs :=
|
||
let add n := add_lemma m ignore_errors as_simp n hs >>= to_hinst_lemmas_core as_simp ns
|
||
in do
|
||
/- First check if n is the name of a function with equational lemmas associated with it -/
|
||
eqns ← tactic.get_eqn_lemmas_for tt n,
|
||
match eqns with
|
||
| [] := do
|
||
/- n is not the name of a function definition or it does not have equational lemmas, then check if it is a lemma -/
|
||
add n
|
||
| _ := do
|
||
p ← is_prop_decl n,
|
||
if p then add n /- n is a proposition -/
|
||
else do
|
||
/- Add equational lemmas to resulting hinst_lemmas -/
|
||
new_hs ← to_hinst_lemmas_core tt eqns hs,
|
||
to_hinst_lemmas_core as_simp ns new_hs
|
||
end
|
||
|
||
meta def mk_hinst_lemma_attr_core (attr_name : name) (as_simp : bool) : command :=
|
||
do t ← to_expr ``(caching_user_attribute hinst_lemmas),
|
||
a ← attr_name^.to_expr,
|
||
b ← if as_simp then to_expr ``(tt) else to_expr ``(ff),
|
||
v ← to_expr ``({name := %%a,
|
||
descr := "hinst_lemma attribute",
|
||
mk_cache := λ ns, to_hinst_lemmas_core reducible ff %%b ns hinst_lemmas.mk,
|
||
dependencies := [`reducibility] } : caching_user_attribute hinst_lemmas),
|
||
add_decl (declaration.defn attr_name [] t v reducibility_hints.abbrev ff),
|
||
attribute.register attr_name
|
||
|
||
meta def mk_hinst_lemma_attrs_core (as_simp : bool) : list name → command
|
||
| [] := skip
|
||
| (n::ns) :=
|
||
(mk_hinst_lemma_attr_core n as_simp >> mk_hinst_lemma_attrs_core ns)
|
||
<|>
|
||
(do type ← infer_type (expr.const n []),
|
||
expected ← to_expr ``(caching_user_attribute hinst_lemmas),
|
||
(is_def_eq type expected
|
||
<|> fail ("failed to create hinst_lemma attribute '" ++ n^.to_string ++ "', declaration already exists and has different type.")),
|
||
mk_hinst_lemma_attrs_core ns)
|
||
|
||
meta def merge_hinst_lemma_attrs (m : transparency) (ignore_errors as_simp : bool) : list name → hinst_lemmas → tactic hinst_lemmas
|
||
| [] hs := return hs
|
||
| (attr::attrs) hs := do
|
||
ns ← attribute.get_instances attr,
|
||
new_hs ← to_hinst_lemmas_core m ignore_errors as_simp ns hs,
|
||
merge_hinst_lemma_attrs attrs new_hs
|
||
|
||
/--
|
||
Create a new "cached" attribute (attr_name : caching_user_attribute hinst_lemmas).
|
||
It also creates "cached" attributes for each attr_names and simp_attr_names if they have not been defined
|
||
yet. Moreover, the hinst_lemmas for attr_name will be the union of the lemmas tagged with
|
||
attr_name, attrs_name, and simp_attr_names.
|
||
For the ones in simp_attr_names, we use the left-hand-side of the conclusion as the pattern.
|
||
-/
|
||
meta def mk_hinst_lemma_attr_set (attr_name : name) (attr_names : list name) (simp_attr_names : list name) : command :=
|
||
do mk_hinst_lemma_attrs_core ff attr_names,
|
||
mk_hinst_lemma_attrs_core tt simp_attr_names,
|
||
t ← to_expr ``(caching_user_attribute hinst_lemmas),
|
||
a ← attr_name^.to_expr,
|
||
l1 ← list_name.to_expr attr_names,
|
||
l2 ← list_name.to_expr simp_attr_names,
|
||
v ← to_expr ``({name := %%a,
|
||
descr := "hinst_lemma attribute set",
|
||
mk_cache := λ ns,
|
||
let aux1 : list name := %%l1,
|
||
aux2 : list name := %%l2 in
|
||
do {
|
||
hs₁ ← to_hinst_lemmas_core reducible ff ff ns hinst_lemmas.mk,
|
||
hs₂ ← merge_hinst_lemma_attrs reducible ff ff aux1 hs₁,
|
||
merge_hinst_lemma_attrs reducible ff tt aux2 hs₂},
|
||
dependencies := [`reducibility] ++ %%l1 ++ %%l2 } : caching_user_attribute hinst_lemmas),
|
||
add_decl (declaration.defn attr_name [] t v reducibility_hints.abbrev ff),
|
||
attribute.register attr_name
|
||
|
||
meta def get_hinst_lemmas_for_attr (attr_name : name) : tactic hinst_lemmas :=
|
||
do
|
||
cnst ← return (expr.const attr_name []),
|
||
attr ← eval_expr (caching_user_attribute hinst_lemmas) cnst,
|
||
caching_user_attribute.get_cache attr
|
||
|
||
structure ematch_config :=
|
||
(max_instances : nat := 10000)
|
||
(max_generation : nat := 10)
|
||
|
||
/- Ematching -/
|
||
meta constant ematch_state : Type
|
||
meta constant ematch_state.mk : ematch_config → ematch_state
|
||
meta constant ematch_state.internalize : ematch_state → expr → tactic ematch_state
|
||
|
||
namespace tactic
|
||
meta constant ematch_core : transparency → cc_state → ematch_state → hinst_lemma → expr → tactic (list (expr × expr) × cc_state × ematch_state)
|
||
meta constant ematch_all_core : transparency → cc_state → ematch_state → hinst_lemma → bool → tactic (list (expr × expr) × cc_state × ematch_state)
|
||
|
||
meta def ematch : cc_state → ematch_state → hinst_lemma → expr → tactic (list (expr × expr) × cc_state × ematch_state) :=
|
||
ematch_core reducible
|
||
|
||
meta def ematch_all : cc_state → ematch_state → hinst_lemma → bool → tactic (list (expr × expr) × cc_state × ematch_state) :=
|
||
ematch_all_core reducible
|
||
end tactic
|