| author | wenzelm | 
| Thu, 10 Mar 2016 22:49:15 +0100 | |
| changeset 62592 | 4832491d1376 | 
| parent 61844 | 007d3b34080f | 
| child 63709 | d68d10fdec78 | 
| permissions | -rw-r--r-- | 
| 54540 | 1 | (* Title: HOL/Tools/coinduction.ML | 
| 54026 | 2 | Author: Johannes Hölzl, TU Muenchen | 
| 3 | Author: Dmitriy Traytel, TU Muenchen | |
| 4 | Copyright 2013 | |
| 5 | ||
| 6 | Coinduction method that avoids some boilerplate compared to coinduct. | |
| 7 | *) | |
| 8 | ||
| 9 | signature COINDUCTION = | |
| 10 | sig | |
| 61844 | 11 | val coinduction_context_tactic: term list -> thm option -> thm list -> int -> context_tactic | 
| 12 | val coinduction_tac: Proof.context -> term list -> thm option -> thm list -> int -> tactic | |
| 54026 | 13 | end; | 
| 14 | ||
| 15 | structure Coinduction : COINDUCTION = | |
| 16 | struct | |
| 17 | ||
| 18 | fun filter_in_out _ [] = ([], []) | |
| 58814 | 19 | | filter_in_out P (x :: xs) = | 
| 20 | let | |
| 21 | val (ins, outs) = filter_in_out P xs; | |
| 22 | in | |
| 23 | if P x then (x :: ins, outs) else (ins, x :: outs) | |
| 24 | end; | |
| 54026 | 25 | |
| 26 | fun ALLGOALS_SKIP skip tac st = | |
| 27 | let fun doall n = if n = skip then all_tac else tac n THEN doall (n - 1) | |
| 59582 | 28 | in doall (Thm.nprems_of st) st end; | 
| 54026 | 29 | |
| 30 | fun THEN_ALL_NEW_SKIP skip tac1 tac2 i st = | |
| 31 | st |> (tac1 i THEN (fn st' => | |
| 59582 | 32 | Seq.INTERVAL tac2 (i + skip) (i + Thm.nprems_of st' - Thm.nprems_of st) st')); | 
| 54026 | 33 | |
| 34 | fun DELETE_PREMS_AFTER skip tac i st = | |
| 35 | let | |
| 59582 | 36 | val n = nth (Thm.prems_of st) (i - 1) |> Logic.strip_assums_hyp |> length; | 
| 54026 | 37 | in | 
| 59498 
50b60f501b05
proper context for resolve_tac, eresolve_tac, dresolve_tac, forward_tac etc.;
 wenzelm parents: 
59158diff
changeset | 38 | (THEN_ALL_NEW_SKIP skip tac (REPEAT_DETERM_N n o eresolve0_tac [thin_rl])) i st | 
| 54026 | 39 | end; | 
| 40 | ||
| 61844 | 41 | fun coinduction_context_tactic raw_vars opt_raw_thm prems = | 
| 61841 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 42 | CONTEXT_SUBGOAL (fn (goal, i) => fn (ctxt, st) => | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 43 | let | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 44 | val lhs_of_eq = HOLogic.dest_Trueprop #> HOLogic.dest_eq #> fst; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 45 | fun find_coinduct t = | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 46 | Induct.find_coinductP ctxt t @ | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 47 | (try (Induct.find_coinductT ctxt o fastype_of o lhs_of_eq) t |> the_default []); | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 48 | val raw_thm = | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 49 | (case opt_raw_thm of | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 50 | SOME raw_thm => raw_thm | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 51 | | NONE => goal |> Logic.strip_assums_concl |> find_coinduct |> hd); | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 52 | val skip = Integer.max 1 (Rule_Cases.get_consumes raw_thm) - 1; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 53 | val cases = Rule_Cases.get raw_thm |> fst; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 54 | in | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 55 | ((Object_Logic.rulify_tac ctxt THEN' | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 56 | Method.insert_tac ctxt prems THEN' | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 57 | Object_Logic.atomize_prems_tac ctxt THEN' | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 58 |         DELETE_PREMS_AFTER skip (Subgoal.FOCUS (fn {concl, context = ctxt, params, prems, ...} =>
 | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 59 | let | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 60 | val vars = raw_vars @ map (Thm.term_of o snd) params; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 61 | val names_ctxt = ctxt | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 62 | |> fold Variable.declare_names vars | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 63 | |> fold Variable.declare_thm (raw_thm :: prems); | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 64 | val thm_concl = Thm.cprop_of raw_thm |> strip_imp_concl; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 65 | val (instT, inst) = Thm.match (thm_concl, concl); | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 66 | val rhoTs = map (fn (v, T) => (TVar v, Thm.typ_of T)) instT; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 67 | val rhots = map (fn (v, t) => (Var v, Thm.term_of t)) inst; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 68 | val xs = hd (Thm.prems_of raw_thm) |> HOLogic.dest_Trueprop |> strip_comb |> snd | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 69 | |> map (subst_atomic_types rhoTs); | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 70 | val raw_eqs = map (fn x => (x, AList.lookup op aconv rhots x |> the)) xs; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 71 | val ((names, ctxt), Ts) = map_split (apfst fst o dest_Var o fst) raw_eqs | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 72 | |>> (fn names => Variable.variant_fixes names names_ctxt) ; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 73 | val eqs = | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 74 |               @{map 3} (fn name => fn T => fn (_, rhs) =>
 | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 75 | HOLogic.mk_eq (Free (name, T), rhs)) | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 76 | names Ts raw_eqs; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 77 | val phi = eqs @ map (HOLogic.dest_Trueprop o Thm.prop_of) prems | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 78 | |> try (Library.foldr1 HOLogic.mk_conj) | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 79 |               |> the_default @{term True}
 | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 80 | |> Ctr_Sugar_Util.list_exists_free vars | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 81 | |> Term.map_abs_vars (Variable.revert_fixed ctxt) | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 82 | |> fold_rev Term.absfree (names ~~ Ts) | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 83 | |> Thm.cterm_of ctxt; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 84 | val thm = infer_instantiate' ctxt [SOME phi] raw_thm; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 85 | val e = length eqs; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 86 | val p = length prems; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 87 | in | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 88 | HEADGOAL (EVERY' [resolve_tac ctxt [thm], | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 89 | EVERY' (map (fn var => | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 90 | resolve_tac ctxt | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 91 | [infer_instantiate' ctxt [NONE, SOME (Thm.cterm_of ctxt var)] exI]) vars), | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 92 | if p = 0 then Ctr_Sugar_Util.CONJ_WRAP' (K (resolve_tac ctxt [refl])) eqs | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 93 | else | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 94 | REPEAT_DETERM_N e o (resolve_tac ctxt [conjI] THEN' resolve_tac ctxt [refl]) THEN' | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 95 | Ctr_Sugar_Util.CONJ_WRAP' (resolve_tac ctxt o single) prems, | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 96 | K (ALLGOALS_SKIP skip | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 97 | (REPEAT_DETERM_N (length vars) o (eresolve_tac ctxt [exE] THEN' rotate_tac ~1) THEN' | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 98 |                  DELETE_PREMS_AFTER 0 (Subgoal.FOCUS (fn {prems, params, context = ctxt, ...} =>
 | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 99 | (case prems of | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 100 | [] => all_tac | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 101 | | inv :: case_prems => | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 102 | let | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 103 | val (init, last) = funpow_yield (p + e - 1) (HOLogic.conj_elim ctxt) inv; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 104 | val inv_thms = init @ [last]; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 105 | val eqs = take e inv_thms; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 106 | fun is_local_var t = | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 107 | member (fn (t, (_, t')) => t aconv (Thm.term_of t')) params t; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 108 | val (eqs, assms') = | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 109 | filter_in_out (is_local_var o lhs_of_eq o Thm.prop_of) eqs; | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 110 | val assms = assms' @ drop e inv_thms | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 111 | in | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 112 | HEADGOAL (Method.insert_tac ctxt (assms @ case_prems)) THEN | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 113 | Ctr_Sugar_General_Tactics.unfold_thms_tac ctxt eqs | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 114 | end)) ctxt)))]) | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 115 | end) ctxt) THEN' | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 116 | K (prune_params_tac ctxt)) i) st | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 117 | |> Seq.maps (fn st' => | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 118 | CONTEXT_CASES (Rule_Cases.make_common ctxt (Thm.prop_of st') cases) all_tac (ctxt, st')) | 
| 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 119 | end); | 
| 54026 | 120 | |
| 61844 | 121 | fun coinduction_tac ctxt x1 x2 x3 x4 = | 
| 122 | Method.NO_CONTEXT_TACTIC ctxt (coinduction_context_tactic x1 x2 x3 x4); | |
| 123 | ||
| 124 | ||
| 54026 | 125 | local | 
| 126 | ||
| 127 | val ruleN = "rule" | |
| 128 | val arbitraryN = "arbitrary" | |
| 129 | fun single_rule [rule] = rule | |
| 130 | | single_rule _ = error "Single rule expected"; | |
| 131 | ||
| 132 | fun named_rule k arg get = | |
| 133 | Scan.lift (Args.$$$ k -- Args.colon) |-- Scan.repeat arg :|-- | |
| 134 | (fn names => Scan.peek (fn context => Scan.succeed (names |> map (fn name => | |
| 135 | (case get (Context.proof_of context) name of SOME x => x | |
| 136 |       | NONE => error ("No rule for " ^ k ^ " " ^ quote name))))));
 | |
| 137 | ||
| 138 | fun rule get_type get_pred = | |
| 55951 
c07d184aebe9
tuned signature -- more uniform check_type_name/read_type_name;
 wenzelm parents: 
54742diff
changeset | 139 |   named_rule Induct.typeN (Args.type_name {proper = false, strict = false}) get_type ||
 | 
| 55954 | 140 |   named_rule Induct.predN (Args.const {proper = false, strict = false}) get_pred ||
 | 
| 141 |   named_rule Induct.setN (Args.const {proper = false, strict = false}) get_pred ||
 | |
| 54026 | 142 | Scan.lift (Args.$$$ ruleN -- Args.colon) |-- Attrib.thms; | 
| 143 | ||
| 59158 | 144 | val coinduct_rule = | 
| 145 | rule Induct.lookup_coinductT Induct.lookup_coinductP >> single_rule; | |
| 54026 | 146 | |
| 147 | fun unless_more_args scan = Scan.unless (Scan.lift | |
| 148 | ((Args.$$$ arbitraryN || Args.$$$ Induct.typeN || | |
| 149 | Args.$$$ Induct.predN || Args.$$$ Induct.setN || Args.$$$ ruleN) -- Args.colon)) scan; | |
| 150 | ||
| 151 | val arbitrary = Scan.optional (Scan.lift (Args.$$$ arbitraryN -- Args.colon) |-- | |
| 152 | Scan.repeat1 (unless_more_args Args.term)) []; | |
| 153 | ||
| 154 | in | |
| 155 | ||
| 58814 | 156 | val _ = | 
| 157 | Theory.setup | |
| 158 |     (Method.setup @{binding coinduction}
 | |
| 159 | (arbitrary -- Scan.option coinduct_rule >> | |
| 61841 
4d3527b94f2a
more general types Proof.method / context_tactic;
 wenzelm parents: 
60784diff
changeset | 160 | (fn (arbitrary, opt_rule) => fn _ => fn facts => | 
| 61844 | 161 | Seq.DETERM (coinduction_context_tactic arbitrary opt_rule facts 1))) | 
| 58814 | 162 | "coinduction on types or predicates/sets"); | 
| 54026 | 163 | |
| 164 | end; | |
| 165 | ||
| 166 | end; |