feat(library/tools/mini_crush): add tracing messages, and more examples

This commit is contained in:
Leonardo de Moura 2017-02-19 17:27:09 -08:00
parent 0fb5a01f17
commit a41aac0e6a
3 changed files with 192 additions and 8 deletions

View file

@ -81,20 +81,42 @@ meta def collect_inductive_from_target : tactic (list expr) :=
do S ← target >>= collect_inductive,
return $ list.qsort (λ e₁ e₂, size e₁ < size e₂) $ S^.to_list
meta def collect_inductive_hyps : tactic (list expr) :=
local_context >>= mfoldl (λ r h, mcond (is_inductive h) (return $ h::r) (return r)) []
/- Induction -/
meta def try_induction_aux (cont : tactic unit) : list expr → tactic unit
meta def try_induction_aux (cont : expr → tactic unit) : list expr → tactic unit
| [] := failed
| (e::es) := (step (induction e); cont; now) <|> try_induction_aux es
| (e::es) := (step (induction e); cont e; now) <|> try_induction_aux es
meta def try_induction (cont : tactic unit) : tactic unit :=
focus1 $ collect_inductive_from_target >>= mfilter (λ e, return $ e^.is_local_constant) >>= try_induction_aux cont
meta def try_induction (cont : expr → tactic unit) : tactic unit :=
focus1 $ collect_inductive_hyps >>= try_induction_aux cont
meta def strategy_1 (cfg : simp_config := {}) : tactic unit :=
meta def report_failure (s : name) (e : option expr := none) : tactic unit :=
when_tracing `mini_crush $
match e with
| none := trace ("FAILED '" ++ to_string s ++ "' at")
| some e := (do p ← pp e, trace (to_fmt "FAILED '" ++ to_fmt s ++ "' processing " ++ p ++ to_fmt " at")) <|> trace ("FAILED '" ++ to_string s ++ "' at")
end
>> trace_state >> trace "--------------" >> failed
meta def close_or_fail (s : name) (e : expr) : tactic unit :=
now
<|> triv <|> reflexivity reducible <|> contradiction
<|> (rsimp >> now) <|> try_for 1000 reflexivity
<|> report_failure s (some e)
meta def strategy_1 (cfg : simp_config := {}) (n : name := "strategy 1") : tactic unit :=
do s ← simp_lemmas.mk_default >>= add_relevant_eqns,
try_induction (simph_intros_using s cfg >> (now <|> triv <|> reflexivity reducible <|> contradiction <|> rsimp <|> try_for 1000 reflexivity))
try_induction (λ e, simph_intros_using s cfg >> close_or_fail n e)
meta def strategy_2 (cfg : simp_config := {}) : tactic unit :=
intros >> strategy_1 cfg "strategy 2"
end mini_crush
meta def mini_crush :=
mini_crush.strategy_1
<|>
mini_crush.strategy_2

View file

@ -1,3 +1,4 @@
import tools.mini_crush
/- "Proving in the Large" chapter of CPDT -/
inductive exp : Type
@ -19,8 +20,8 @@ def times (k : nat) : exp → exp
attribute [simp] exp_eval times mul_add
theorem eval_times (k e) : exp_eval (times k e) = k * exp_eval e :=
by induction e; simph
theorem eval_times : ∀ (k e), exp_eval (times k e) = k * exp_eval e :=
by mini_crush
def reassoc : exp → exp
| (Const n) := (Const n)

161
tests/lean/run/cpdt3.lean Normal file
View file

@ -0,0 +1,161 @@
import tools.mini_crush
/-
This corresponds to Chapter 2 of CPDT, Some Quick Examples
-/
open list
inductive binop : Type
| Plus
| Times
open binop
inductive exp : Type
| Const : nat → exp
| Binop : binop → exp → exp → exp
open exp
def binop_denote : binop → nat → nat → nat
| Plus := add
| Times := mul
def exp_denote : exp → nat
| (Const n) := n
| (Binop b e1 e2) := (binop_denote b) (exp_denote e1) (exp_denote e2)
inductive instr : Type
| iConst : → instr
| iBinop : binop → instr
open instr
@[reducible]
def prog := list instr
def stack := list nat
def instr_denote (i : instr) (s : stack) : option stack :=
match i with
| (iConst n) := some (n :: s)
| (iBinop b) :=
match s with
| (arg1 :: arg2 :: s') := some ((binop_denote b) arg1 arg2 :: s')
| _ := none
end
end
def prog_denote : prog → stack → option stack
| nil s := some s
| (i :: p') s :=
match instr_denote i s with
| none := none
| (some s') := prog_denote p' s'
end
def compile : exp → prog
| (Const n) := iConst n :: nil
| (Binop b e1 e2) := compile e2 ++ compile e1 ++ iBinop b :: nil
/- This example needs a few facts from the list library. -/
@[simp] theorem compile_correct' :
∀ e p s, prog_denote (compile e ++ p) s = prog_denote p (exp_denote e :: s) :=
by intro; mini_crush
@[simp] theorem compile_correct : ∀ e, prog_denote (compile e) nil = some (exp_denote e :: nil) :=
by mini_crush
inductive type : Type
| Nat
| Bool
open type
inductive tbinop : type → type → type → Type
| TPlus : tbinop Nat Nat Nat
| TTimes : tbinop Nat Nat Nat
| TEq : ∀ t, tbinop t t Bool
| TLt : tbinop Nat Nat Bool
open tbinop
inductive texp : type → Type
| TNConst : nat → texp Nat
| TBConst : bool → texp Bool
| TBinop : ∀ {t1 t2 t}, tbinop t1 t2 t → texp t1 → texp t2 → texp t
open texp
def type_denote : type → Type
| Nat := nat
| Bool := bool
/- To simulate CPDT we need the next three operations. -/
def beq_nat (m n : ) : bool := if m = n then tt else ff
def eqb (b₁ b₂ : bool) : bool := if b₁ = b₂ then tt else ff
def leb (m n : ) : bool := if m < n then tt else ff
def tbinop_denote : Π {arg1 arg2 res : type},
tbinop arg1 arg2 res → type_denote arg1 → type_denote arg2 → type_denote res
| ._ ._ ._ TPlus := (add : )
| ._ ._ ._ TTimes := (mul : )
| ._ ._ ._ (TEq Nat) := beq_nat
| ._ ._ ._ (TEq Bool) := eqb
| ._ ._ ._ TLt := leb
def texp_denote : Π {t : type}, texp t → type_denote t
| ._ (TNConst n) := n
| ._ (TBConst b) := b
| ._ (@TBinop _ _ _ b e1 e2) := (tbinop_denote b) (texp_denote e1) (texp_denote e2)
@[reducible]
def tstack := list type
inductive tinstr : tstack → tstack → Type
| TiNConst : Π s, nat → tinstr s (Nat :: s)
| TiBConst : Π s, bool → tinstr s (Bool :: s)
| TiBinop : Π {arg1 arg2 res s}, tbinop arg1 arg2 res → tinstr (arg1 :: arg2 :: s) (res :: s)
open tinstr
inductive tprog : tstack → tstack → Type
| TNil : Π {s}, tprog s s
| TCons : Π {s1 s2 s3}, tinstr s1 s2 → tprog s2 s3 → tprog s1 s3
open tprog
def vstack : tstack → Type
| nil := unit
| (t :: ts') := type_denote t × vstack ts'
def tinstr_denote : Π {ts ts' : tstack}, tinstr ts ts' → vstack ts → vstack ts'
| ._ ._ (TiNConst ts n) := λ s, (n, s)
| ._ ._ (TiBConst ts b) := λ s, (b, s)
| ._ ._ (@TiBinop arg1 arg2 res s b) := λ ⟨arg1, ⟨arg2, s'⟩⟩, ((tbinop_denote b) arg1 arg2, s')
def tprog_denote : Π {ts ts' : tstack}, tprog ts ts' → vstack ts → vstack ts'
| ._ ._ (@TNil _) := λ s, s
| ._ ._ (@TCons _ _ _ i p') := λ s, tprog_denote p' (tinstr_denote i s)
def tconcat : Π {ts ts' ts'' : tstack}, tprog ts ts' → tprog ts' ts'' → tprog ts ts''
| ._ ._ ts'' (@TNil _) p' := p'
| ._ ._ ts'' (@TCons _ _ _ i p1) p' := TCons i (tconcat p1 p')
def tcompile : Π {t : type}, texp t → Π ts : tstack, tprog ts (t :: ts)
| ._ (TNConst n) ts := TCons (TiNConst _ n) TNil
| ._ (TBConst b) ts := TCons (TiBConst _ b) TNil
| ._ (@TBinop _ _ _ b e1 e2) ts := tconcat (tcompile e2 _)
(tconcat (tcompile e1 _) (TCons (TiBinop b) TNil))
@[simp] lemma tconcat_correct : ∀ ts ts' ts'' (p : tprog ts ts') (p' : tprog ts' ts'') (s : vstack ts),
tprog_denote (tconcat p p') s = tprog_denote p' (tprog_denote p s) :=
by mini_crush
@[simp] lemma tcompile_correct' : ∀ t (e : texp t) ts (s : vstack ts),
tprog_denote (tcompile e ts) s = (texp_denote e, s) :=
by intros t e; mini_crush
theorem tcompile_correct :
∀ t (e : texp t), tprog_denote (tcompile e nil) () = (texp_denote e, ()) :=
by mini_crush