35 val n = nth (Thm.prems_of st) (i - 1) |> Logic.strip_assums_hyp |> length; |
35 val n = nth (Thm.prems_of st) (i - 1) |> Logic.strip_assums_hyp |> length; |
36 in |
36 in |
37 (THEN_ALL_NEW_SKIP skip tac (REPEAT_DETERM_N n o eresolve0_tac [thin_rl])) i st |
37 (THEN_ALL_NEW_SKIP skip tac (REPEAT_DETERM_N n o eresolve0_tac [thin_rl])) i st |
38 end; |
38 end; |
39 |
39 |
40 fun coinduction_tac ctxt raw_vars opt_raw_thm prems = HEADGOAL (SUBGOAL_CASES (fn (goal, _) => |
40 fun coinduction_tac raw_vars opt_raw_thm prems = |
41 let |
41 CONTEXT_SUBGOAL (fn (goal, i) => fn (ctxt, st) => |
42 val lhs_of_eq = HOLogic.dest_Trueprop #> HOLogic.dest_eq #> fst; |
42 let |
43 fun find_coinduct t = |
43 val lhs_of_eq = HOLogic.dest_Trueprop #> HOLogic.dest_eq #> fst; |
44 Induct.find_coinductP ctxt t @ |
44 fun find_coinduct t = |
45 (try (Induct.find_coinductT ctxt o fastype_of o lhs_of_eq) t |> the_default []) |
45 Induct.find_coinductP ctxt t @ |
46 val raw_thm = |
46 (try (Induct.find_coinductT ctxt o fastype_of o lhs_of_eq) t |> the_default []); |
47 (case opt_raw_thm of |
47 val raw_thm = |
48 SOME raw_thm => raw_thm |
48 (case opt_raw_thm of |
49 | NONE => goal |> Logic.strip_assums_concl |> find_coinduct |> hd); |
49 SOME raw_thm => raw_thm |
50 val skip = Integer.max 1 (Rule_Cases.get_consumes raw_thm) - 1 |
50 | NONE => goal |> Logic.strip_assums_concl |> find_coinduct |> hd); |
51 val cases = Rule_Cases.get raw_thm |> fst |
51 val skip = Integer.max 1 (Rule_Cases.get_consumes raw_thm) - 1; |
52 in |
52 val cases = Rule_Cases.get raw_thm |> fst; |
53 HEADGOAL ( |
53 in |
54 Object_Logic.rulify_tac ctxt THEN' |
54 ((Object_Logic.rulify_tac ctxt THEN' |
55 Method.insert_tac prems THEN' |
55 Method.insert_tac ctxt prems THEN' |
56 Object_Logic.atomize_prems_tac ctxt THEN' |
56 Object_Logic.atomize_prems_tac ctxt THEN' |
57 DELETE_PREMS_AFTER skip (Subgoal.FOCUS (fn {concl, context = ctxt, params, prems, ...} => |
57 DELETE_PREMS_AFTER skip (Subgoal.FOCUS (fn {concl, context = ctxt, params, prems, ...} => |
58 let |
58 let |
59 val vars = raw_vars @ map (Thm.term_of o snd) params; |
59 val vars = raw_vars @ map (Thm.term_of o snd) params; |
60 val names_ctxt = ctxt |
60 val names_ctxt = ctxt |
61 |> fold Variable.declare_names vars |
61 |> fold Variable.declare_names vars |
62 |> fold Variable.declare_thm (raw_thm :: prems); |
62 |> fold Variable.declare_thm (raw_thm :: prems); |
63 val thm_concl = Thm.cprop_of raw_thm |> strip_imp_concl; |
63 val thm_concl = Thm.cprop_of raw_thm |> strip_imp_concl; |
64 val (instT, inst) = Thm.match (thm_concl, concl); |
64 val (instT, inst) = Thm.match (thm_concl, concl); |
65 val rhoTs = map (fn (v, T) => (TVar v, Thm.typ_of T)) instT; |
65 val rhoTs = map (fn (v, T) => (TVar v, Thm.typ_of T)) instT; |
66 val rhots = map (fn (v, t) => (Var v, Thm.term_of t)) inst; |
66 val rhots = map (fn (v, t) => (Var v, Thm.term_of t)) inst; |
67 val xs = hd (Thm.prems_of raw_thm) |> HOLogic.dest_Trueprop |> strip_comb |> snd |
67 val xs = hd (Thm.prems_of raw_thm) |> HOLogic.dest_Trueprop |> strip_comb |> snd |
68 |> map (subst_atomic_types rhoTs); |
68 |> map (subst_atomic_types rhoTs); |
69 val raw_eqs = map (fn x => (x, AList.lookup op aconv rhots x |> the)) xs; |
69 val raw_eqs = map (fn x => (x, AList.lookup op aconv rhots x |> the)) xs; |
70 val ((names, ctxt), Ts) = map_split (apfst fst o dest_Var o fst) raw_eqs |
70 val ((names, ctxt), Ts) = map_split (apfst fst o dest_Var o fst) raw_eqs |
71 |>> (fn names => Variable.variant_fixes names names_ctxt) ; |
71 |>> (fn names => Variable.variant_fixes names names_ctxt) ; |
72 val eqs = |
72 val eqs = |
73 @{map 3} (fn name => fn T => fn (_, rhs) => |
73 @{map 3} (fn name => fn T => fn (_, rhs) => |
74 HOLogic.mk_eq (Free (name, T), rhs)) |
74 HOLogic.mk_eq (Free (name, T), rhs)) |
75 names Ts raw_eqs; |
75 names Ts raw_eqs; |
76 val phi = eqs @ map (HOLogic.dest_Trueprop o Thm.prop_of) prems |
76 val phi = eqs @ map (HOLogic.dest_Trueprop o Thm.prop_of) prems |
77 |> try (Library.foldr1 HOLogic.mk_conj) |
77 |> try (Library.foldr1 HOLogic.mk_conj) |
78 |> the_default @{term True} |
78 |> the_default @{term True} |
79 |> Ctr_Sugar_Util.list_exists_free vars |
79 |> Ctr_Sugar_Util.list_exists_free vars |
80 |> Term.map_abs_vars (Variable.revert_fixed ctxt) |
80 |> Term.map_abs_vars (Variable.revert_fixed ctxt) |
81 |> fold_rev Term.absfree (names ~~ Ts) |
81 |> fold_rev Term.absfree (names ~~ Ts) |
82 |> Thm.cterm_of ctxt; |
82 |> Thm.cterm_of ctxt; |
83 val thm = infer_instantiate' ctxt [SOME phi] raw_thm; |
83 val thm = infer_instantiate' ctxt [SOME phi] raw_thm; |
84 val e = length eqs; |
84 val e = length eqs; |
85 val p = length prems; |
85 val p = length prems; |
86 in |
86 in |
87 HEADGOAL (EVERY' [resolve_tac ctxt [thm], |
87 HEADGOAL (EVERY' [resolve_tac ctxt [thm], |
88 EVERY' (map (fn var => |
88 EVERY' (map (fn var => |
89 resolve_tac ctxt |
89 resolve_tac ctxt |
90 [infer_instantiate' ctxt [NONE, SOME (Thm.cterm_of ctxt var)] exI]) vars), |
90 [infer_instantiate' ctxt [NONE, SOME (Thm.cterm_of ctxt var)] exI]) vars), |
91 if p = 0 then Ctr_Sugar_Util.CONJ_WRAP' (K (resolve_tac ctxt [refl])) eqs |
91 if p = 0 then Ctr_Sugar_Util.CONJ_WRAP' (K (resolve_tac ctxt [refl])) eqs |
92 else |
92 else |
93 REPEAT_DETERM_N e o (resolve_tac ctxt [conjI] THEN' resolve_tac ctxt [refl]) THEN' |
93 REPEAT_DETERM_N e o (resolve_tac ctxt [conjI] THEN' resolve_tac ctxt [refl]) THEN' |
94 Ctr_Sugar_Util.CONJ_WRAP' (resolve_tac ctxt o single) prems, |
94 Ctr_Sugar_Util.CONJ_WRAP' (resolve_tac ctxt o single) prems, |
95 K (ALLGOALS_SKIP skip |
95 K (ALLGOALS_SKIP skip |
96 (REPEAT_DETERM_N (length vars) o (eresolve_tac ctxt [exE] THEN' rotate_tac ~1) THEN' |
96 (REPEAT_DETERM_N (length vars) o (eresolve_tac ctxt [exE] THEN' rotate_tac ~1) THEN' |
97 DELETE_PREMS_AFTER 0 (Subgoal.FOCUS (fn {prems, params, context = ctxt, ...} => |
97 DELETE_PREMS_AFTER 0 (Subgoal.FOCUS (fn {prems, params, context = ctxt, ...} => |
98 (case prems of |
98 (case prems of |
99 [] => all_tac |
99 [] => all_tac |
100 | inv :: case_prems => |
100 | inv :: case_prems => |
101 let |
101 let |
102 val (init, last) = funpow_yield (p + e - 1) (HOLogic.conj_elim ctxt) inv; |
102 val (init, last) = funpow_yield (p + e - 1) (HOLogic.conj_elim ctxt) inv; |
103 val inv_thms = init @ [last]; |
103 val inv_thms = init @ [last]; |
104 val eqs = take e inv_thms; |
104 val eqs = take e inv_thms; |
105 fun is_local_var t = |
105 fun is_local_var t = |
106 member (fn (t, (_, t')) => t aconv (Thm.term_of t')) params t; |
106 member (fn (t, (_, t')) => t aconv (Thm.term_of t')) params t; |
107 val (eqs, assms') = |
107 val (eqs, assms') = |
108 filter_in_out (is_local_var o lhs_of_eq o Thm.prop_of) eqs; |
108 filter_in_out (is_local_var o lhs_of_eq o Thm.prop_of) eqs; |
109 val assms = assms' @ drop e inv_thms |
109 val assms = assms' @ drop e inv_thms |
110 in |
110 in |
111 HEADGOAL (Method.insert_tac (assms @ case_prems)) THEN |
111 HEADGOAL (Method.insert_tac ctxt (assms @ case_prems)) THEN |
112 Ctr_Sugar_General_Tactics.unfold_thms_tac ctxt eqs |
112 Ctr_Sugar_General_Tactics.unfold_thms_tac ctxt eqs |
113 end)) ctxt)))]) |
113 end)) ctxt)))]) |
114 end) ctxt) THEN' |
114 end) ctxt) THEN' |
115 K (prune_params_tac ctxt)) |
115 K (prune_params_tac ctxt)) i) st |
116 #> Seq.maps (fn st => |
116 |> Seq.maps (fn st' => |
117 CASES (Rule_Cases.make_common ctxt (Thm.prop_of st) cases) all_tac st) |
117 CONTEXT_CASES (Rule_Cases.make_common ctxt (Thm.prop_of st') cases) all_tac (ctxt, st')) |
118 end)); |
118 end); |
119 |
119 |
120 local |
120 local |
121 |
121 |
122 val ruleN = "rule" |
122 val ruleN = "rule" |
123 val arbitraryN = "arbitrary" |
123 val arbitraryN = "arbitrary" |