| author | wenzelm | 
| Sun, 03 Sep 2023 16:44:07 +0200 | |
| changeset 78639 | ca56952b7322 | 
| parent 74563 | 042041c0ebeb | 
| permissions | -rw-r--r-- | 
| 28308 | 1 | (* Title: Tools/induct_tacs.ML | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 2 | Author: Makarius | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 3 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 4 | Unstructured induction and cases analysis. | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 5 | *) | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 6 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 7 | signature INDUCT_TACS = | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 8 | sig | 
| 59802 | 9 | val case_tac: Proof.context -> string -> (binding * string option * mixfix) list -> | 
| 59826 | 10 | thm option -> int -> tactic | 
| 11 | val induct_tac: Proof.context -> string option list list -> | |
| 12 | thm list option -> int -> tactic | |
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 13 | end | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 14 | |
| 45133 | 15 | structure Induct_Tacs: INDUCT_TACS = | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 16 | struct | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 17 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 18 | (* case analysis *) | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 19 | |
| 46836 | 20 | fun check_type ctxt (t, pos) = | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 21 | let | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 22 | val u = singleton (Variable.polymorphic ctxt) t; | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 23 | val U = Term.fastype_of u; | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 24 | val _ = Term.is_TVar U andalso | 
| 55715 
bc04f1ab3c3a
tuned messages -- prefer quote before Position.here, which might be just \<here>;
 wenzelm parents: 
55111diff
changeset | 25 |       error ("Cannot determine type of " ^
 | 
| 
bc04f1ab3c3a
tuned messages -- prefer quote before Position.here, which might be just \<here>;
 wenzelm parents: 
55111diff
changeset | 26 | quote (Syntax.string_of_term ctxt u) ^ Position.here pos); | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 27 | in (u, U) end; | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 28 | |
| 59829 | 29 | fun case_tac ctxt s fixes opt_rule = SUBGOAL (fn (goal, i) => | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 30 | let | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 31 | val rule = | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 32 | (case opt_rule of | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 33 | SOME rule => rule | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 34 | | NONE => | 
| 59802 | 35 | let | 
| 59827 
04e569577c18
proper Rule_Insts.read_term, e.g. to enable case_tac using "_";
 wenzelm parents: 
59826diff
changeset | 36 | val (t, ctxt') = ctxt | 
| 59829 | 37 | |> Rule_Insts.goal_context goal |> #2 | 
| 59827 
04e569577c18
proper Rule_Insts.read_term, e.g. to enable case_tac using "_";
 wenzelm parents: 
59826diff
changeset | 38 | |> Context_Position.set_visible false | 
| 
04e569577c18
proper Rule_Insts.read_term, e.g. to enable case_tac using "_";
 wenzelm parents: 
59826diff
changeset | 39 | |> Rule_Insts.read_term s; | 
| 
04e569577c18
proper Rule_Insts.read_term, e.g. to enable case_tac using "_";
 wenzelm parents: 
59826diff
changeset | 40 | val pos = Syntax.read_input_pos s; | 
| 59802 | 41 | in | 
| 59827 
04e569577c18
proper Rule_Insts.read_term, e.g. to enable case_tac using "_";
 wenzelm parents: 
59826diff
changeset | 42 | (case Induct.find_casesT ctxt' (#2 (check_type ctxt' (t, pos))) of | 
| 59802 | 43 | rule :: _ => rule | 
| 44 |             | [] => @{thm case_split})
 | |
| 45 | end); | |
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 46 | val _ = Method.trace ctxt [rule]; | 
| 59829 | 47 | in | 
| 48 | (case Induct.vars_of (Thm.term_of (Thm.cprem_of rule 1)) handle THM _ => [] of | |
| 49 | Var (xi, _) :: _ => Rule_Insts.res_inst_tac ctxt [((xi, Position.none), s)] fixes rule i | |
| 50 | | _ => no_tac) | |
| 51 | end); | |
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 52 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 53 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 54 | (* induction *) | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 55 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 56 | local | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 57 | |
| 59755 | 58 | fun prep_var (Var (xi, _), SOME x) = SOME ((xi, Position.none), x) | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 59 | | prep_var _ = NONE; | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 60 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 61 | fun prep_inst (concl, xs) = | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 62 | let val vs = Induct.vars_of concl | 
| 33957 | 63 | in map_filter prep_var (drop (length vs - length xs) vs ~~ xs) end; | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 64 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 65 | in | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 66 | |
| 59830 | 67 | fun induct_tac ctxt varss opt_rules i st = | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 68 | let | 
| 59830 | 69 | val goal = Thm.cprem_of st i; | 
| 70 | val (_, goal_ctxt) = Rule_Insts.goal_context (Thm.term_of goal) ctxt | |
| 60695 
757549b4bbe6
Variable.focus etc.: optional bindings provided by user;
 wenzelm parents: 
59830diff
changeset | 71 | and ((_, goal'), _) = Variable.focus_cterm NONE goal ctxt; | 
| 59830 | 72 | val (prems, concl) = Logic.strip_horn (Thm.term_of goal'); | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 73 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 74 | fun induct_var name = | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 75 | let | 
| 59830 | 76 | val t = Syntax.read_term goal_ctxt name; | 
| 59795 | 77 | val pos = Syntax.read_input_pos name; | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 78 | val (x, _) = Term.dest_Free t handle TERM _ => | 
| 46836 | 79 |           error ("Induction argument not a variable: " ^
 | 
| 59830 | 80 | quote (Syntax.string_of_term goal_ctxt t) ^ Position.here pos); | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 81 | val eq_x = fn Free (y, _) => x = y | _ => false; | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 82 | val _ = | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 83 | if Term.exists_subterm eq_x concl then () | 
| 46836 | 84 | else | 
| 85 |             error ("No such variable in subgoal: " ^
 | |
| 59830 | 86 | quote (Syntax.string_of_term goal_ctxt t) ^ Position.here pos); | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 87 | val _ = | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 88 | if (exists o Term.exists_subterm) eq_x prems then | 
| 46836 | 89 |             warning ("Induction variable occurs also among premises: " ^
 | 
| 59830 | 90 | quote (Syntax.string_of_term goal_ctxt t) ^ Position.here pos) | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 91 | else (); | 
| 59830 | 92 | in #1 (check_type goal_ctxt (t, pos)) end; | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 93 | |
| 59830 | 94 | val argss = (map o map o Option.map) induct_var varss; | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 95 | val rule = | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 96 | (case opt_rules of | 
| 33368 | 97 | SOME rules => #2 (Rule_Cases.strict_mutual_rule ctxt rules) | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 98 | | NONE => | 
| 33368 | 99 | (case map_filter (Rule_Cases.mutual_rule ctxt) (Induct.get_inductT ctxt argss) of | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 100 | (_, rule) :: _ => rule | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 101 |           | [] => raise THM ("No induction rules", 0, [])));
 | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 102 | |
| 54742 
7a86358a3c0b
proper context for basic Simplifier operations: rewrite_rule, rewrite_goals_rule, rewrite_goals_tac etc.;
 wenzelm parents: 
48992diff
changeset | 103 | val rule' = rule |> Conv.fconv_rule (Conv.concl_conv ~1 (Object_Logic.atomize ctxt)); | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 104 | val _ = Method.trace ctxt [rule']; | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 105 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 106 | val concls = Logic.dest_conjunctions (Thm.concl_of rule); | 
| 40722 
441260986b63
make two copies (!) of Library.UnequalLengths coincide with ListPair.UnequalLengths;
 wenzelm parents: 
36960diff
changeset | 107 | val insts = maps prep_inst (concls ~~ varss) handle ListPair.UnequalLengths => | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 108 | error "Induction rule has different numbers of variables"; | 
| 59780 | 109 | in Rule_Insts.res_inst_tac ctxt insts [] rule' i st end | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 110 | handle THM _ => Seq.empty; | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 111 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 112 | end; | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 113 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 114 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 115 | (* method syntax *) | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 116 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 117 | local | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 118 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 119 | val rule_spec = Scan.lift (Args.$$$ "rule" -- Args.$$$ ":"); | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 120 | val opt_rule = Scan.option (rule_spec |-- Attrib.thm); | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 121 | val opt_rules = Scan.option (rule_spec |-- Attrib.thms); | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 122 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 123 | val varss = | 
| 55111 | 124 | Parse.and_list' | 
| 74563 | 125 | (Scan.repeat (Scan.unless rule_spec (Scan.lift (Args.maybe Parse.embedded_inner_syntax)))); | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 126 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 127 | in | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 128 | |
| 58826 | 129 | val _ = | 
| 130 | Theory.setup | |
| 67149 | 131 | (Method.setup \<^binding>\<open>case_tac\<close> | 
| 74563 | 132 | (Args.goal_spec -- Scan.lift (Parse.embedded_inner_syntax -- Parse.for_fixes) -- opt_rule >> | 
| 59826 | 133 | (fn ((quant, (s, xs)), r) => fn ctxt => SIMPLE_METHOD'' quant (case_tac ctxt s xs r))) | 
| 58826 | 134 | "unstructured case analysis on types" #> | 
| 67149 | 135 | Method.setup \<^binding>\<open>induct_tac\<close> | 
| 58826 | 136 | (Args.goal_spec -- varss -- opt_rules >> | 
| 59826 | 137 | (fn ((quant, vs), rs) => fn ctxt => SIMPLE_METHOD'' quant (induct_tac ctxt vs rs))) | 
| 58826 | 138 | "unstructured induction on types"); | 
| 27326 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 139 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 140 | end; | 
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 141 | |
| 
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
 wenzelm parents: diff
changeset | 142 | end; |