fix to eliminate excessive case-splits in the recursion equations, by Luca Dixon
authorpaulson
Fri, 20 Aug 2004 12:20:09 +0200
changeset 15150c7af682b9ee5
parent 15149 c5c4884634b7
child 15151 429666b09783
fix to eliminate excessive case-splits in the recursion equations, by Luca Dixon
TFL/casesplit.ML
TFL/isand.ML
TFL/post.ML
src/HOL/IsaMakefile
src/HOL/Recdef.thy
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/TFL/casesplit.ML	Fri Aug 20 12:20:09 2004 +0200
     1.3 @@ -0,0 +1,310 @@
     1.4 +(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *) 
     1.5 +(*  Title:      TFL/casesplit.ML
     1.6 +    Author:     Lucas Dixon, University of Edinburgh
     1.7 +                lucas.dixon@ed.ac.uk
     1.8 +    Date:       17 Aug 2004
     1.9 +*)
    1.10 +(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *) 
    1.11 +(*  DESCRIPTION:
    1.12 +
    1.13 +    A structure that defines a tactic to program case splits. 
    1.14 +
    1.15 +    casesplit_free :
    1.16 +      string * Term.type -> int -> Thm.thm -> Thm.thm Seq.seq
    1.17 +
    1.18 +    casesplit_name : 
    1.19 +      string -> int -> Thm.thm -> Thm.thm Seq.seq
    1.20 +
    1.21 +    These use the induction theorem associated with the recursive data
    1.22 +    type to be split. 
    1.23 +
    1.24 +    The structure includes a function to try and recursively split a
    1.25 +    conjecture into a list sub-theorems: 
    1.26 +
    1.27 +    splitto : Thm.thm list -> Thm.thm -> Thm.thm
    1.28 +*)
    1.29 +(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *) 
    1.30 +
    1.31 +(* logic-specific *)
    1.32 +signature CASE_SPLIT_DATA =
    1.33 +sig
    1.34 +  val dest_Trueprop : Term.term -> Term.term
    1.35 +  val mk_Trueprop : Term.term -> Term.term
    1.36 +  val read_cterm : Sign.sg -> string -> Thm.cterm
    1.37 +end;
    1.38 +
    1.39 +(* for HOL *)
    1.40 +structure CaseSplitData_HOL : CASE_SPLIT_DATA = 
    1.41 +struct
    1.42 +val dest_Trueprop = HOLogic.dest_Trueprop;
    1.43 +val mk_Trueprop = HOLogic.mk_Trueprop;
    1.44 +val read_cterm = HOLogic.read_cterm;
    1.45 +end;
    1.46 +
    1.47 +
    1.48 +signature CASE_SPLIT =
    1.49 +sig
    1.50 +  (* failure to find a free to split on *)
    1.51 +  exception find_split_exp of string
    1.52 +
    1.53 +  (* getting a case split thm from the induction thm *)
    1.54 +  val case_thm_of_ty : Sign.sg -> Term.typ -> Thm.thm
    1.55 +  val cases_thm_of_induct_thm : Thm.thm -> Thm.thm
    1.56 +
    1.57 +  (* case split tactics *)
    1.58 +  val casesplit_free :
    1.59 +      string * Term.typ -> int -> Thm.thm -> Thm.thm Seq.seq
    1.60 +  val casesplit_name : string -> int -> Thm.thm -> Thm.thm Seq.seq
    1.61 +
    1.62 +  (* finding a free var to split *)
    1.63 +  val find_term_split :
    1.64 +      Term.term * Term.term -> (string * Term.typ) Library.option
    1.65 +  val find_thm_split :
    1.66 +      Thm.thm -> int -> Thm.thm -> (string * Term.typ) Library.option
    1.67 +  val find_thms_split :
    1.68 +      Thm.thm list -> int -> Thm.thm -> (string * Term.typ) Library.option
    1.69 +
    1.70 +  (* try to recursively split conjectured thm to given list of thms *)
    1.71 +  val splitto : Thm.thm list -> Thm.thm -> Thm.thm
    1.72 +
    1.73 +  (* for use with the recdef package *)
    1.74 +  val derive_init_eqs :
    1.75 +      Sign.sg ->
    1.76 +      (Thm.thm * int) list -> Term.term list -> (Thm.thm * int) list
    1.77 +end;
    1.78 +
    1.79 +functor CaseSplitFUN(Data : CASE_SPLIT_DATA) =
    1.80 +struct
    1.81 +
    1.82 +(* beta-eta contract the theorem *)
    1.83 +fun beta_eta_contract thm = 
    1.84 +    let
    1.85 +      val thm2 = equal_elim (Thm.beta_conversion true (Thm.cprop_of thm)) thm
    1.86 +      val thm3 = equal_elim (Thm.eta_conversion (Thm.cprop_of thm2)) thm2
    1.87 +    in thm3 end;
    1.88 +
    1.89 +(* make a casethm from an induction thm *)
    1.90 +val cases_thm_of_induct_thm = 
    1.91 +     Seq.hd o (ALLGOALS (fn i => REPEAT (etac Drule.thin_rl i)));
    1.92 +
    1.93 +(* get the case_thm (my version) from a type *)
    1.94 +fun case_thm_of_ty sgn ty  = 
    1.95 +    let 
    1.96 +      val dtypestab = DatatypePackage.get_datatypes_sg sgn;
    1.97 +      val ty_str = case ty of 
    1.98 +                     Type(ty_str, _) => ty_str
    1.99 +                   | TFree(s,_)  => raise ERROR_MESSAGE 
   1.100 +                                            ("Free type: " ^ s)   
   1.101 +                   | TVar((s,i),_) => raise ERROR_MESSAGE 
   1.102 +                                            ("Free variable: " ^ s)   
   1.103 +      val dt = case (Symtab.lookup (dtypestab,ty_str))
   1.104 +                of Some dt => dt
   1.105 +                 | None => raise ERROR_MESSAGE ("Not a Datatype: " ^ ty_str)
   1.106 +    in
   1.107 +      cases_thm_of_induct_thm (#induction dt)
   1.108 +    end;
   1.109 +
   1.110 +(* 
   1.111 + val ty = (snd o hd o map Term.dest_Free o Term.term_frees) t;  
   1.112 +*)
   1.113 +
   1.114 +
   1.115 +(* for use when there are no prems to the subgoal *)
   1.116 +(* does a case split on the given variable *)
   1.117 +fun mk_casesplit_goal_thm sgn (vstr,ty) gt = 
   1.118 +    let 
   1.119 +      val x = Free(vstr,ty)
   1.120 +      val abst = Abs(vstr, ty, Term.abstract_over (x, gt));
   1.121 +
   1.122 +      val ctermify = Thm.cterm_of sgn;
   1.123 +      val ctypify = Thm.ctyp_of sgn;
   1.124 +      val case_thm = case_thm_of_ty sgn ty;
   1.125 +
   1.126 +      val abs_ct = ctermify abst;
   1.127 +      val free_ct = ctermify x;
   1.128 +
   1.129 +      val casethm_vars = rev (Term.term_vars (Thm.concl_of case_thm));
   1.130 +       
   1.131 +      val tsig = Sign.tsig_of sgn;
   1.132 +      val casethm_tvars = Term.term_tvars (Thm.concl_of case_thm);
   1.133 +      val (Pv, Dv, type_insts) = 
   1.134 +          case (Thm.concl_of case_thm) of 
   1.135 +            (_ $ ((Pv as Var(P,Pty)) $ (Dv as Var(D, Dty)))) => 
   1.136 +            (Pv, Dv, 
   1.137 +             Vartab.dest (Type.typ_match tsig (Vartab.empty, (Dty, ty))))
   1.138 +          | _ => raise ERROR_MESSAGE ("not a valid case thm");
   1.139 +      val type_cinsts = map (apsnd ctypify) type_insts;
   1.140 +      val cPv = ctermify (Sign.inst_term_tvars sgn type_insts Pv);
   1.141 +      val cDv = ctermify (Sign.inst_term_tvars sgn type_insts Dv);
   1.142 +    in
   1.143 +      (beta_eta_contract 
   1.144 +         (case_thm
   1.145 +            |> Thm.instantiate (type_cinsts, []) 
   1.146 +            |> Thm.instantiate ([], [(cPv, abs_ct), (cDv, free_ct)])))
   1.147 +    end;
   1.148 +
   1.149 +
   1.150 +(* for use when there are no prems to the subgoal *)
   1.151 +(* does a case split on the given variable (Free fv) *)
   1.152 +fun casesplit_free fv i th = 
   1.153 +    let 
   1.154 +      val gt = Data.dest_Trueprop (nth_elem( i - 1, Thm.prems_of th));
   1.155 +      val sgn = Thm.sign_of_thm th;
   1.156 +    in 
   1.157 +      Tactic.rtac (mk_casesplit_goal_thm sgn fv gt) i th
   1.158 +    end;
   1.159 +
   1.160 +(* for use when there are no prems to the subgoal *)
   1.161 +(* does a case split on the given variable *)
   1.162 +fun casesplit_name vstr i th = 
   1.163 +    let 
   1.164 +      val gt = Data.dest_Trueprop (nth_elem( i - 1, Thm.prems_of th));
   1.165 +      val freets = Term.term_frees gt;
   1.166 +      fun getter x = let val (n,ty) = Term.dest_Free x in 
   1.167 +                       if vstr = n then Some (n,ty) else None end;
   1.168 +      val (n,ty) = case Library.get_first getter freets 
   1.169 +                of Some (n, ty) => (n, ty)
   1.170 +                 | _ => raise ERROR_MESSAGE ("no such variable " ^ vstr);
   1.171 +      val sgn = Thm.sign_of_thm th;
   1.172 +    in 
   1.173 +      Tactic.rtac (mk_casesplit_goal_thm sgn (n,ty) gt) i th
   1.174 +    end;
   1.175 +
   1.176 +
   1.177 +(* small example: 
   1.178 +Goal "P (x :: nat) & (C y --> Q (y :: nat))";
   1.179 +by (rtac (thm "conjI") 1);
   1.180 +val th = topthm();
   1.181 +val i = 2;
   1.182 +val vstr = "y";
   1.183 +
   1.184 +by (casesplit_name "y" 2);
   1.185 +
   1.186 +val th = topthm();
   1.187 +val i = 1;
   1.188 +val th' = casesplit_name "x" i th;
   1.189 +*)
   1.190 +
   1.191 +
   1.192 +(* the find_XXX_split functions are simply doing a lightwieght (I
   1.193 +think) term matching equivalent to find where to do the next split *)
   1.194 +
   1.195 +(* assuming two twems are identical except for a free in one at a
   1.196 +subterm, or constant in another, ie assume that one term is a plit of
   1.197 +another, then gives back the free variable that has been split. *)
   1.198 +exception find_split_exp of string
   1.199 +fun find_term_split (Free v, _ $ _) = Some v
   1.200 +  | find_term_split (Free v, Const _) = Some v
   1.201 +  | find_term_split (Free v, Abs _) = Some v (* do we really want this case? *)
   1.202 +  | find_term_split (a $ b, a2 $ b2) = 
   1.203 +    (case find_term_split (a, a2) of 
   1.204 +       None => find_term_split (b,b2)  
   1.205 +     | vopt => vopt)
   1.206 +  | find_term_split (Abs(_,ty,t1), Abs(_,ty2,t2)) = 
   1.207 +    find_term_split (t1, t2)
   1.208 +  | find_term_split (Const (x,ty), Const(x2,ty2)) = 
   1.209 +    if x = x2 then None else (* keep searching *)
   1.210 +    raise find_split_exp (* stop now *)
   1.211 +            "Terms are not identical upto a free varaible! (Consts)"
   1.212 +  | find_term_split (Bound i, Bound j) =     
   1.213 +    if i = j then None else (* keep searching *)
   1.214 +    raise find_split_exp (* stop now *)
   1.215 +            "Terms are not identical upto a free varaible! (Bound)"
   1.216 +  | find_term_split (a, b) = 
   1.217 +    raise find_split_exp (* stop now *)
   1.218 +            "Terms are not identical upto a free varaible! (Other)";
   1.219 +
   1.220 +(* assume that "splitth" is a case split form of subgoal i of "genth",
   1.221 +then look for a free variable to split, breaking the subgoal closer to
   1.222 +splitth. *)
   1.223 +fun find_thm_split splitth i genth =
   1.224 +    find_term_split (Logic.get_goal (Thm.prop_of genth) i, 
   1.225 +                     Thm.concl_of splitth) handle find_split_exp _ => None;
   1.226 +
   1.227 +(* as above but searches "splitths" for a theorem that suggest a case split *)
   1.228 +fun find_thms_split splitths i genth =
   1.229 +    Library.get_first (fn sth => find_thm_split sth i genth) splitths;
   1.230 +
   1.231 +
   1.232 +(* split the subgoal i of "genth" until we get to a member of
   1.233 +splitths. Assumes that genth will be a general form of splitths, that
   1.234 +can be case-split, as needed. Otherwise fails. Note: We assume that
   1.235 +all of "splitths" are aplit to the same level, and thus it doesn't
   1.236 +matter which one we choose to look for the next split. Simply add
   1.237 +search on splitthms and plit variable, to change this.  *)
   1.238 +(* Note: possible efficiency measure: when a case theorem is no longer
   1.239 +useful, drop it? *)
   1.240 +(* Note: This should not be a separate tactic but integrated into the
   1.241 +case split done during recdef's case analysis, this would avoid us
   1.242 +having to (re)search for variables to split. *)
   1.243 +fun splitto splitths genth = 
   1.244 +    let 
   1.245 +      val _ = assert (not (null splitths)) "splitto: no given splitths";
   1.246 +      val sgn = Thm.sign_of_thm genth;
   1.247 +
   1.248 +      (* check if we are a member of splitths - FIXME: quicker and 
   1.249 +      more flexible with discrim net. *)
   1.250 +      fun solve_by_splitth th split = biresolution false [(false,split)] 1 th;
   1.251 +
   1.252 +      fun split th = 
   1.253 +          (case find_thms_split splitths 1 th of 
   1.254 +             None => raise ERROR_MESSAGE "splitto: cannot find variable to split on"
   1.255 +            | Some v => 
   1.256 +             let 
   1.257 +               val gt = Data.dest_Trueprop (nth_elem(0, Thm.prems_of th));
   1.258 +               val split_thm = mk_casesplit_goal_thm sgn v gt;
   1.259 +               val (subthms, expf) = IsaND.fixed_subgoal_thms split_thm;
   1.260 +             in 
   1.261 +               expf (map recsplitf subthms)
   1.262 +             end)
   1.263 +
   1.264 +      and recsplitf th = 
   1.265 +          (* note: multiple unifiers! we only take the first element,
   1.266 +             probably fine -- there is probably only one anyway. *)
   1.267 +          (case Library.get_first (Seq.pull o solve_by_splitth th) splitths of
   1.268 +             None => split th
   1.269 +           | Some (solved_th, more) => solved_th)
   1.270 +    in
   1.271 +      recsplitf genth
   1.272 +    end;
   1.273 +
   1.274 +
   1.275 +(* Note: We dont do this if wf conditions fail to be solved, as each
   1.276 +case may have a different wf condition - we could group the conditions
   1.277 +togeather and say that they must be true to solve the general case,
   1.278 +but that would hide from the user which sub-case they were related
   1.279 +to. Probably this is not important, and it would work fine, but I
   1.280 +prefer leaving more fine grain control to the user. *)
   1.281 +
   1.282 +(* derive eqs, assuming strict, ie the rules have no assumptions = all
   1.283 +   the well-foundness conditions have been solved. *)
   1.284 +local
   1.285 +  fun get_related_thms i = 
   1.286 +      mapfilter ((fn (r,x) => if x = i then Some r else None));
   1.287 +      
   1.288 +  fun solve_eq (th, [], i) = 
   1.289 +      raise ERROR_MESSAGE "derive_init_eqs: missing rules"
   1.290 +    | solve_eq (th, [a], i) = (a, i)
   1.291 +    | solve_eq (th, splitths as (_ :: _), i) = (splitto splitths th,i);
   1.292 +in
   1.293 +fun derive_init_eqs sgn rules eqs = 
   1.294 +    let 
   1.295 +      val eqths = map (Thm.trivial o (Thm.cterm_of sgn) o Data.mk_Trueprop) 
   1.296 +                      eqs
   1.297 +    in
   1.298 +      (rev o map solve_eq)
   1.299 +        (Library.foldln 
   1.300 +           (fn (e,i) => 
   1.301 +               (curry (op ::)) (e, (get_related_thms (i - 1) rules), i - 1)) 
   1.302 +           eqths [])
   1.303 +    end;
   1.304 +end;
   1.305 +(* 
   1.306 +    val (rs_hwfc, unhidefs) = Library.split_list (map hide_prems rules)
   1.307 +    (map2 (op |>) (ths, expfs))
   1.308 +*)
   1.309 +
   1.310 +end;
   1.311 +
   1.312 +
   1.313 +structure CaseSplit = CaseSplitFUN(CaseSplitData_HOL);
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/TFL/isand.ML	Fri Aug 20 12:20:09 2004 +0200
     2.3 @@ -0,0 +1,241 @@
     2.4 +(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *) 
     2.5 +(*  Title:      TFL/isand.ML
     2.6 +    Author:     Lucas Dixon, University of Edinburgh
     2.7 +                lucas.dixon@ed.ac.uk
     2.8 +    Date:       6 Aug 2004
     2.9 +*)
    2.10 +(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *) 
    2.11 +(*  DESCRIPTION:
    2.12 +
    2.13 +    Natural Deduction tools
    2.14 +
    2.15 +    For working with Isbaelle theorem in a natural detuction style,
    2.16 +    ie, not having to deal with meta level quantified varaibles,
    2.17 +    instead, we work with newly introduced frees, and hide the
    2.18 +    "all"'s, exporting results from theorems proved with the frees, to
    2.19 +    solve the all cases of the previous goal. 
    2.20 +
    2.21 +    Note: A nice idea: allow esxporting to solve any subgoal, thus
    2.22 +    allowing the interleaving of proof, or provide a structure for the
    2.23 +    ordering of proof, thus allowing proof attempts in parrelle, but
    2.24 +    recording the order to apply things in.
    2.25 +*)
    2.26 +
    2.27 +structure IsaND =
    2.28 +struct
    2.29 +
    2.30 +(* Solve *some* subgoal of "th" directly by "sol" *)
    2.31 +(* Note: this is probably what Markus ment to do upon export of a
    2.32 +"show" but maybe he used RS/rtac intead, which would wrongly lead to
    2.33 +failing if there are premices to the shown goal. *)
    2.34 +fun solve_with sol th = 
    2.35 +    let fun solvei 0 = Seq.empty
    2.36 +          | solvei i = 
    2.37 +            Seq.append (bicompose false (false,sol,0) i th, 
    2.38 +                        solvei (i - 1))
    2.39 +    in
    2.40 +      solvei (Thm.nprems_of th)
    2.41 +    end;
    2.42 +
    2.43 +
    2.44 +(* fix parameters of a subgoal "i", as free variables, and create an
    2.45 +exporting function that will use the result of this proved goal to
    2.46 +show the goal in the original theorem. 
    2.47 +
    2.48 +Note, an advantage of this over Isar is that it supports instantiation
    2.49 +of unkowns in the earlier theorem, ie we can do instantiation of meta
    2.50 +vars! *)
    2.51 +fun fix_alls' i th = 
    2.52 +    let 
    2.53 +      val t = (prop_of th); 
    2.54 +      val names = Term.add_term_names (t,[]);
    2.55 +      val gt = Logic.get_goal t i;
    2.56 +      val body = Term.strip_all_body gt;
    2.57 +      val alls = rev (Term.strip_all_vars gt);
    2.58 +      val fvs = map Free 
    2.59 +                    ((Term.variantlist (map fst alls, names)) 
    2.60 +                       ~~ (map snd alls));
    2.61 +      val sgn = Thm.sign_of_thm th;
    2.62 +      val ctermify = Thm.cterm_of sgn;
    2.63 +      val cfvs = rev (map ctermify fvs);
    2.64 +
    2.65 +      val body' = (subst_bounds (fvs,body));
    2.66 +      val gthi0 = Thm.trivial (ctermify body');
    2.67 +      
    2.68 +      (* Given a thm justifying subgoal i, solve subgoal i *)
    2.69 +      (* Note: fails if there are choices! *)
    2.70 +      fun exportf thi = 
    2.71 +          Drule.compose_single (Drule.forall_intr_list cfvs thi, 
    2.72 +                                i, th)
    2.73 +    in
    2.74 +      (gthi0, exportf)
    2.75 +    end;
    2.76 +
    2.77 +(* small example: 
    2.78 +Goal "!! x. [| False; C x |] ==> P x";
    2.79 +val th = topthm();
    2.80 +val i = 1;
    2.81 +val (goalth, expf) = fix_alls i (topthm());
    2.82 +*)
    2.83 +
    2.84 +
    2.85 +(* a nicer version of the above that leaves only a single subgoal (the
    2.86 +other subgoals are hidden hyps, that the exporter suffles about)
    2.87 +namely the subgoal that we were trying to solve. *)
    2.88 +
    2.89 +fun fix_alls i th = 
    2.90 +    let 
    2.91 +      val (gthi, exportf) = fix_alls' i th
    2.92 +      val gthi' = Drule.rotate_prems 1 gthi
    2.93 +
    2.94 +      val sgn = Thm.sign_of_thm th;
    2.95 +      val ctermify = Thm.cterm_of sgn;
    2.96 +
    2.97 +      val prems = tl (Thm.prems_of gthi)
    2.98 +      val cprems = map ctermify prems;
    2.99 +      val aprems = map Thm.assume cprems;
   2.100 +
   2.101 +      val exportf' = 
   2.102 +          exportf o (Drule.implies_intr_list cprems)
   2.103 +    in
   2.104 +      (Drule.implies_elim_list gthi' aprems, exportf')
   2.105 +    end;
   2.106 +
   2.107 +(* small example: 
   2.108 +Goal "P x";
   2.109 +val i = 1;
   2.110 +val th = topthm();
   2.111 +val x = fix_alls (topthm()) 1;
   2.112 +
   2.113 +Goal "!! x. [| False; C x |] ==> P x";
   2.114 +val th = topthm();
   2.115 +val i = 1;
   2.116 +val (goalth, expf) = fix_alls' th i;
   2.117 +
   2.118 +val (premths, goalth2, expf2) = assume_prems 1 goalth;
   2.119 +val False_th = nth_elem (0,premths);
   2.120 +val anything = False_th RS (thm "FalseE");
   2.121 +val th2 = anything RS goalth2;
   2.122 +val th1 = expf2 th2;
   2.123 +val final_th = flat (map expf th1);
   2.124 +*)
   2.125 +
   2.126 +
   2.127 +(* assume the premises of subgoal "i", this gives back a list of
   2.128 +assumed theorems that are the premices of subgoal i, it also gives
   2.129 +back a new goal thm and an exporter, the new goalthm is as the old
   2.130 +one, but without the premices, and the exporter will use a proof of
   2.131 +the new goalthm, possibly using the assumed premices, to shoe the
   2.132 +orginial goal. *)
   2.133 +
   2.134 +(* Note: Dealing with meta vars, need to meta-level-all them in the
   2.135 +shyps, which we can later instantiate with a specific value.... ? 
   2.136 +think about this... maybe need to introduce some new fixed vars and
   2.137 +then remove them again at the end... like I do with rw_inst. *)
   2.138 +fun assume_prems i th =
   2.139 +    let 
   2.140 +      val t = (prop_of th); 
   2.141 +      val gt = Logic.get_goal t i;
   2.142 +      val _ = case Term.strip_all_vars gt of [] => () 
   2.143 +              | _ => raise ERROR_MESSAGE "assume_prems: goal has params"
   2.144 +      val body = gt;
   2.145 +      val prems = Logic.strip_imp_prems body;
   2.146 +      val concl = Logic.strip_imp_concl body;
   2.147 +
   2.148 +      val sgn = Thm.sign_of_thm th;
   2.149 +      val ctermify = Thm.cterm_of sgn;
   2.150 +      val cprems = map ctermify prems;
   2.151 +      val aprems = map Thm.assume cprems;
   2.152 +      val gthi = Thm.trivial (ctermify concl);
   2.153 +
   2.154 +      fun explortf thi = 
   2.155 +          Drule.compose (Drule.implies_intr_list cprems thi, 
   2.156 +                         i, th)
   2.157 +    in
   2.158 +      (aprems, gthi, explortf)
   2.159 +    end;
   2.160 +(* small example: 
   2.161 +Goal "False ==> b";
   2.162 +val th = topthm();
   2.163 +val i = 1;
   2.164 +val (prems, goalth, expf) = assume_prems i (topthm());
   2.165 +val F = hd prems;
   2.166 +val FalseE = thm "FalseE";
   2.167 +val anything = F RS FalseE;
   2.168 +val thi = anything RS goalth;
   2.169 +val res' = expf thi;
   2.170 +*)
   2.171 +
   2.172 +
   2.173 +(* Fixme: allow different order of subgoals *)
   2.174 +fun subgoal_thms th = 
   2.175 +    let 
   2.176 +      val t = (prop_of th); 
   2.177 +
   2.178 +      val prems = Logic.strip_imp_prems t;
   2.179 +
   2.180 +      val sgn = Thm.sign_of_thm th;
   2.181 +      val ctermify = Thm.cterm_of sgn;
   2.182 +
   2.183 +      val aprems = map (Thm.trivial o ctermify) prems;
   2.184 +
   2.185 +      fun explortf premths = 
   2.186 +          Drule.implies_elim_list th premths
   2.187 +    in
   2.188 +      (aprems, explortf)
   2.189 +    end;
   2.190 +(* small example: 
   2.191 +Goal "A & B";
   2.192 +by (rtac conjI 1);
   2.193 +val th = topthm();
   2.194 +val (subgoals, expf) = subgoal_thms (topthm());
   2.195 +*)
   2.196 +
   2.197 +(* make all the premices of a theorem hidden, and provide an unhide
   2.198 +function, that will bring them back out at a later point. This is
   2.199 +useful if you want to get back these premices, after having used the
   2.200 +theorem with the premices hidden *)
   2.201 +fun hide_prems th = 
   2.202 +    let 
   2.203 +      val sgn = Thm.sign_of_thm th;
   2.204 +      val ctermify = Thm.cterm_of sgn;
   2.205 +
   2.206 +      val t = (prop_of th);
   2.207 +      val prems = Logic.strip_imp_prems t;
   2.208 +      val cprems = map ctermify prems;
   2.209 +      val aprems = map Thm.trivial cprems;
   2.210 +
   2.211 +      val unhidef = Drule.implies_intr_list cprems;
   2.212 +    in
   2.213 +      (Drule.implies_elim_list th aprems, unhidef)
   2.214 +    end;
   2.215 +
   2.216 +
   2.217 +
   2.218 +
   2.219 +(* Fixme: allow different order of subgoals *)
   2.220 +fun fixed_subgoal_thms th = 
   2.221 +    let 
   2.222 +      val (subgoals, expf) = subgoal_thms th;
   2.223 +
   2.224 +(*       fun export_sg (th, exp) = exp th; *)
   2.225 +      fun export_sgs expfs ths = 
   2.226 +          expf (map2 (op |>) (ths, expfs));
   2.227 +
   2.228 +(*           expf (map export_sg (ths ~~ expfs)); *)
   2.229 +
   2.230 +
   2.231 +
   2.232 +    in 
   2.233 +      apsnd export_sgs (Library.split_list (map (fix_alls 1) subgoals))
   2.234 +    end;
   2.235 +
   2.236 +
   2.237 +(* small example: 
   2.238 +Goal "(!! x. ((C x) ==> (A x)))";
   2.239 +val th = topthm();
   2.240 +val i = 1;
   2.241 +val (subgoals, expf) = fixed_subgoal_thms (topthm());
   2.242 +*)
   2.243 +
   2.244 +end;
   2.245 \ No newline at end of file
     3.1 --- a/TFL/post.ML	Thu Aug 19 12:35:45 2004 +0200
     3.2 +++ b/TFL/post.ML	Fri Aug 20 12:20:09 2004 +0200
     3.3 @@ -195,6 +195,42 @@
     3.4                 error (mesg ^
     3.5                        "\n    (In TFL function " ^ module ^ "." ^ func ^ ")");
     3.6  
     3.7 +
     3.8 +(* Derive the initial equations from the case-split rules to meet the
     3.9 +users specification of the recursive function. 
    3.10 + Note: We don't do this if the wf conditions fail to be solved, as each
    3.11 +case may have a different wf condition. We could group the conditions
    3.12 +together and say that they must be true to solve the general case,
    3.13 +but that would hide from the user which sub-case they were related
    3.14 +to. Probably this is not important, and it would work fine, but, for now, I
    3.15 +prefer leaving more fine-grain control to the user. *)
    3.16 +local
    3.17 +  fun get_related_thms i = 
    3.18 +      mapfilter ((fn (r,x) => if x = i then Some r else None));
    3.19 +
    3.20 +  fun solve_eq (th, [], i) = 
    3.21 +      raise ERROR_MESSAGE "derive_init_eqs: missing rules"
    3.22 +    | solve_eq (th, [a], i) = [(a, i)]
    3.23 +    | solve_eq (th, splitths as (_ :: _), i) = 
    3.24 +      [((standard o ObjectLogic.rulify_no_asm)
    3.25 +          (CaseSplit.splitto splitths th), i)]
    3.26 +      (* if there's an error, pretend nothing happened with this definition 
    3.27 +         We should probably print something out so that the user knows...? *)
    3.28 +      handle ERROR_MESSAGE _ => map (fn x => (x,i)) splitths; 
    3.29 +in
    3.30 +fun derive_init_eqs sgn rules eqs = 
    3.31 +    let 
    3.32 +      val eqths = map (Thm.trivial o (Thm.cterm_of sgn) o HOLogic.mk_Trueprop) 
    3.33 +                      eqs
    3.34 +      fun countlist l = 
    3.35 +          (rev o snd o (foldl (fn ((i,L), e) => (i + 1,(e,i) :: L)))) ((0,[]), l)
    3.36 +    in
    3.37 +      flat (map (fn (e,i) => solve_eq (e, (get_related_thms i rules), i))
    3.38 +                (countlist eqths))
    3.39 +    end;
    3.40 +end;
    3.41 +
    3.42 +
    3.43  (*---------------------------------------------------------------------------
    3.44   * Defining a function with an associated termination relation.
    3.45   *---------------------------------------------------------------------------*)
     4.1 --- a/src/HOL/IsaMakefile	Thu Aug 19 12:35:45 2004 +0200
     4.2 +++ b/src/HOL/IsaMakefile	Fri Aug 20 12:20:09 2004 +0200
     4.3 @@ -80,7 +80,8 @@
     4.4    $(SRC)/Provers/quasi.ML \
     4.5    $(SRC)/Provers/simplifier.ML $(SRC)/Provers/splitter.ML \
     4.6    $(SRC)/Provers/trancl.ML \
     4.7 -  $(SRC)/TFL/dcterm.ML $(SRC)/TFL/post.ML $(SRC)/TFL/rules.ML \
     4.8 +  $(SRC)/TFL/isand.ML $(SRC)/TFL/casesplit.ML $(SRC)/TFL/dcterm.ML\
     4.9 +  $(SRC)/TFL/post.ML $(SRC)/TFL/rules.ML \
    4.10    $(SRC)/TFL/tfl.ML $(SRC)/TFL/thms.ML $(SRC)/TFL/thry.ML \
    4.11    $(SRC)/TFL/usyntax.ML $(SRC)/TFL/utils.ML \
    4.12    Datatype.thy Datatype_Universe.ML Datatype_Universe.thy \
    4.13 @@ -96,7 +97,8 @@
    4.14    Nat.thy NatArith.ML NatArith.thy \
    4.15    Power.thy PreList.thy Product_Type.ML Product_Type.thy \
    4.16    Refute.thy ROOT.ML \
    4.17 -  Recdef.thy Record.thy Relation.ML Relation.thy Relation_Power.ML \
    4.18 +  Recdef.thy Reconstruction.thy Record.thy\
    4.19 +  Relation.ML Relation.thy Relation_Power.ML \
    4.20    Relation_Power.thy LOrder.thy OrderedGroup.thy OrderedGroup.ML Ring_and_Field.thy\
    4.21    Set.ML Set.thy SetInterval.ML SetInterval.thy \
    4.22    Sum_Type.ML Sum_Type.thy Tools/datatype_abs_proofs.ML Tools/datatype_aux.ML \
    4.23 @@ -107,7 +109,7 @@
    4.24    Tools/primrec_package.ML \
    4.25    Tools/prop_logic.ML \
    4.26    Tools/recdef_package.ML Tools/recfun_codegen.ML \
    4.27 -  Tools/record_package.ML \
    4.28 +  Tools/record_package.ML Tools/reconstruction.ML\
    4.29    Tools/refute.ML Tools/refute_isar.ML \
    4.30    Tools/rewrite_hol_proof.ML \
    4.31    Tools/sat_solver.ML \
     5.1 --- a/src/HOL/Recdef.thy	Thu Aug 19 12:35:45 2004 +0200
     5.2 +++ b/src/HOL/Recdef.thy	Fri Aug 20 12:20:09 2004 +0200
     5.3 @@ -8,6 +8,8 @@
     5.4  theory Recdef
     5.5  imports Wellfounded_Relations Datatype
     5.6  files
     5.7 +  ("../TFL/isand.ML")
     5.8 +  ("../TFL/casesplit.ML")
     5.9    ("../TFL/utils.ML")
    5.10    ("../TFL/usyntax.ML")
    5.11    ("../TFL/dcterm.ML")
    5.12 @@ -43,6 +45,8 @@
    5.13  lemma tfl_exE: "\<exists>x. P x ==> \<forall>x. P x --> Q ==> Q"
    5.14    by blast
    5.15  
    5.16 +use "../TFL/isand.ML"
    5.17 +use "../TFL/casesplit.ML"
    5.18  use "../TFL/utils.ML"
    5.19  use "../TFL/usyntax.ML"
    5.20  use "../TFL/dcterm.ML"