src/Provers/eqsubst.ML
author wenzelm
Sat, 08 Oct 2005 20:15:34 +0200
changeset 17795 5b18c3343028
parent 16978 e35b518bffc9
child 18011 685d95c793ff
permissions -rw-r--r--
minor tweaks for Poplog/PML;
     1 (* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)
     2 (*  Title:      Provers/eqsubst.ML
     3     ID:         $Id$
     4     Author:     Lucas Dixon, University of Edinburgh
     5                 lucas.dixon@ed.ac.uk
     6     Modified:   18 Feb 2005 - Lucas -
     7     Created:    29 Jan 2005
     8 *)
     9 (* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)
    10 (*  DESCRIPTION:
    11 
    12     A Tactic to perform a substiution using an equation.
    13 
    14 *)
    15 (* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)
    16 
    17 
    18 
    19 (* Logic specific data stub *)
    20 signature EQRULE_DATA =
    21 sig
    22 
    23   (* to make a meta equality theorem in the current logic *)
    24   val prep_meta_eq : thm -> thm list
    25 
    26 end;
    27 
    28 
    29 (* the signature of an instance of the SQSUBST tactic *)
    30 signature EQSUBST_TAC =
    31 sig
    32 
    33   exception eqsubst_occL_exp of
    34             string * (int list) * (thm list) * int * thm;
    35 
    36   type match
    37   type searchinfo
    38 
    39   val prep_subst_in_asm :
    40          int (* subgoal to subst in *)
    41       -> thm (* target theorem with subgoals *)
    42       -> int (* premise to subst in *)
    43       -> (cterm list (* certified free var placeholders for vars *)
    44           * int (* premice no. to subst *)
    45           * int (* number of assumptions of premice *)
    46           * thm) (* premice as a new theorem for forward reasoning *)
    47          * searchinfo (* search info: prem id etc *)
    48 
    49   val prep_subst_in_asms :
    50          int (* subgoal to subst in *)
    51       -> thm (* target theorem with subgoals *)
    52       -> ((cterm list (* certified free var placeholders for vars *)
    53           * int (* premice no. to subst *)
    54           * int (* number of assumptions of premice *)
    55           * thm) (* premice as a new theorem for forward reasoning *)
    56          * searchinfo) list
    57 
    58   val apply_subst_in_asm :
    59       int (* subgoal *)
    60       -> thm (* overall theorem *)
    61       -> thm (* rule *)
    62       -> (cterm list (* certified free var placeholders for vars *)
    63           * int (* assump no being subst *)
    64           * int (* num of premises of asm *)
    65           * thm) (* premthm *)
    66       * match
    67       -> thm Seq.seq
    68 
    69   val prep_concl_subst :
    70          int (* subgoal *)
    71       -> thm (* overall goal theorem *)
    72       -> (cterm list * thm) * searchinfo (* (cvfs, conclthm), matchf *)
    73 
    74   val apply_subst_in_concl :
    75         int (* subgoal *)
    76         -> thm (* thm with all goals *)
    77         -> cterm list (* certified free var placeholders for vars *)
    78            * thm  (* trivial thm of goal concl *)
    79             (* possible matches/unifiers *)
    80         -> thm (* rule *)
    81         -> match
    82         -> thm Seq.seq (* substituted goal *)
    83 
    84   (* basic notion of search *)
    85   val searchf_tlr_unify_all :
    86       (searchinfo
    87        -> term (* lhs *)
    88        -> match Seq.seq Seq.seq)
    89   val searchf_tlr_unify_valid :
    90       (searchinfo
    91        -> term (* lhs *)
    92        -> match Seq.seq Seq.seq)
    93 
    94   (* specialise search constructor for conclusion skipping occurrences. *)
    95      val skip_first_occs_search :
    96         int -> ('a -> 'b -> 'c Seq.seq Seq.seq) -> 'a -> 'b -> 'c Seq.seq
    97   (* specialised search constructor for assumptions using skips *)
    98      val skip_first_asm_occs_search :
    99         ('a -> 'b -> 'c Seq.seq Seq.seq) ->
   100         'a -> int -> 'b -> 'c IsaPLib.skipseqT
   101 
   102   (* tactics and methods *)
   103   val eqsubst_asm_meth : int list -> thm list -> Proof.method
   104   val eqsubst_asm_tac :
   105       int list -> thm list -> int -> thm -> thm Seq.seq
   106   val eqsubst_asm_tac' :
   107       (* search function with skips *)
   108       (searchinfo -> int -> term -> match IsaPLib.skipseqT)
   109       -> int (* skip to *)
   110       -> thm (* rule *)
   111       -> int (* subgoal number *)
   112       -> thm (* tgt theorem with subgoals *)
   113       -> thm Seq.seq (* new theorems *)
   114 
   115   val eqsubst_meth : int list -> thm list -> Proof.method
   116   val eqsubst_tac :
   117       int list -> thm list -> int -> thm -> thm Seq.seq
   118   val eqsubst_tac' :
   119       (searchinfo -> term -> match Seq.seq)
   120       -> thm -> int -> thm -> thm Seq.seq
   121 
   122   val meth : (bool * int list) * thm list -> Proof.context -> Proof.method
   123   val setup : (Theory.theory -> Theory.theory) list
   124 end;
   125 
   126 
   127 functor EQSubstTacFUN (structure EqRuleData : EQRULE_DATA)
   128   : EQSUBST_TAC
   129 = struct
   130 
   131   (* a type abriviation for match information *)
   132   type match =
   133        ((indexname * (sort * typ)) list (* type instantiations *)
   134         * (indexname * (typ * term)) list) (* term instantiations *)
   135        * (string * typ) list (* fake named type abs env *)
   136        * (string * typ) list (* type abs env *)
   137        * term (* outer term *)
   138 
   139   type searchinfo =
   140        Sign.sg (* sign for matching *)
   141        * int (* maxidx *)
   142        * BasicIsaFTerm.FcTerm (* focusterm to search under *)
   143 
   144 (* FOR DEBUGGING...
   145 type trace_subst_errT = int (* subgoal *)
   146         * thm (* thm with all goals *)
   147         * (Thm.cterm list (* certified free var placeholders for vars *)
   148            * thm)  (* trivial thm of goal concl *)
   149             (* possible matches/unifiers *)
   150         * thm (* rule *)
   151         * (((indexname * typ) list (* type instantiations *)
   152               * (indexname * term) list ) (* term instantiations *)
   153              * (string * typ) list (* Type abs env *)
   154              * term) (* outer term *);
   155 
   156 val trace_subst_err = (ref NONE : trace_subst_errT option ref);
   157 val trace_subst_search = ref false;
   158 exception trace_subst_exp of trace_subst_errT;
   159  *)
   160 
   161 (* also defined in /HOL/Tools/inductive_codegen.ML,
   162    maybe move this to seq.ML ? *)
   163 infix 5 :->;
   164 fun s :-> f = Seq.flat (Seq.map f s);
   165 
   166 (* search from top, left to right, then down *)
   167 fun search_tlr_all_f f ft =
   168     let
   169       fun maux ft =
   170           let val t' = (IsaFTerm.focus_of_fcterm ft)
   171             (* val _ =
   172                 if !trace_subst_search then
   173                   (writeln ("Examining: " ^ (TermLib.string_of_term t'));
   174                    TermLib.writeterm t'; ())
   175                 else (); *)
   176           in
   177           (case t' of
   178             (_ $ _) => Seq.append(maux (IsaFTerm.focus_left ft),
   179                        Seq.cons(f ft,
   180                                   maux (IsaFTerm.focus_right ft)))
   181           | (Abs _) => Seq.cons(f ft, maux (IsaFTerm.focus_abs ft))
   182           | leaf => Seq.single (f ft)) end
   183     in maux ft end;
   184 
   185 (* search from top, left to right, then down *)
   186 fun search_tlr_valid_f f ft =
   187     let
   188       fun maux ft =
   189           let
   190             val hereseq = if IsaFTerm.valid_match_start ft then f ft else Seq.empty
   191           in
   192           (case (IsaFTerm.focus_of_fcterm ft) of
   193             (_ $ _) => Seq.append(maux (IsaFTerm.focus_left ft),
   194                        Seq.cons(hereseq,
   195                                   maux (IsaFTerm.focus_right ft)))
   196           | (Abs _) => Seq.cons(hereseq, maux (IsaFTerm.focus_abs ft))
   197           | leaf => Seq.single (hereseq))
   198           end
   199     in maux ft end;
   200 
   201 (* search all unifications *)
   202 fun searchf_tlr_unify_all (sgn, maxidx, ft) lhs =
   203     IsaFTerm.find_fcterm_matches
   204       search_tlr_all_f
   205       (IsaFTerm.clean_unify_ft sgn maxidx lhs)
   206       ft;
   207 
   208 (* search only for 'valid' unifiers (non abs subterms and non vars) *)
   209 fun searchf_tlr_unify_valid (sgn, maxidx, ft) lhs  =
   210     IsaFTerm.find_fcterm_matches
   211       search_tlr_valid_f
   212       (IsaFTerm.clean_unify_ft sgn maxidx lhs)
   213       ft;
   214 
   215 
   216 (* apply a substitution in the conclusion of the theorem th *)
   217 (* cfvs are certified free var placeholders for goal params *)
   218 (* conclthm is a theorem of for just the conclusion *)
   219 (* m is instantiation/match information *)
   220 (* rule is the equation for substitution *)
   221 fun apply_subst_in_concl i th (cfvs, conclthm) rule m =
   222     (RWInst.rw m rule conclthm)
   223       |> IsaND.unfix_frees cfvs
   224       |> RWInst.beta_eta_contract
   225       |> (fn r => Tactic.rtac r i th);
   226 
   227 (* substitute within the conclusion of goal i of gth, using a meta
   228 equation rule. Note that we assume rule has var indicies zero'd *)
   229 fun prep_concl_subst i gth =
   230     let
   231       val th = Thm.incr_indexes 1 gth;
   232       val tgt_term = Thm.prop_of th;
   233 
   234       val sgn = Thm.sign_of_thm th;
   235       val ctermify = Thm.cterm_of sgn;
   236       val trivify = Thm.trivial o ctermify;
   237 
   238       val (fixedbody, fvs) = IsaND.fix_alls_term i tgt_term;
   239       val cfvs = rev (map ctermify fvs);
   240 
   241       val conclterm = Logic.strip_imp_concl fixedbody;
   242       val conclthm = trivify conclterm;
   243       val maxidx = Term.maxidx_of_term conclterm;
   244       val ft = ((IsaFTerm.focus_right
   245                  o IsaFTerm.focus_left
   246                  o IsaFTerm.fcterm_of_term
   247                  o Thm.prop_of) conclthm)
   248     in
   249       ((cfvs, conclthm), (sgn, maxidx, ft))
   250     end;
   251 
   252 (* substitute using an object or meta level equality *)
   253 fun eqsubst_tac' searchf instepthm i th =
   254     let
   255       val (cvfsconclthm, searchinfo) = prep_concl_subst i th;
   256       val stepthms =
   257           Seq.map Drule.zero_var_indexes
   258                   (Seq.of_list (EqRuleData.prep_meta_eq instepthm));
   259       fun rewrite_with_thm r =
   260           let val (lhs,_) = Logic.dest_equals (Thm.concl_of r);
   261           in (searchf searchinfo lhs)
   262              :-> (apply_subst_in_concl i th cvfsconclthm r) end;
   263     in stepthms :-> rewrite_with_thm end;
   264 
   265 
   266 (* Tactic.distinct_subgoals_tac -- fails to free type variables *)
   267 
   268 (* custom version of distinct subgoals that works with term and
   269    type variables. Asssumes th is in beta-eta normal form.
   270    Also, does nothing if flexflex contraints are present. *)
   271 fun distinct_subgoals th =
   272     if List.null (Thm.tpairs_of th) then
   273       let val (fixes,fixedthm) = IsaND.fix_vars_and_tvars th
   274         val (fixedthconcl,cprems) = IsaND.hide_prems fixedthm
   275       in
   276         IsaND.unfix_frees_and_tfrees
   277           fixes
   278           (Drule.implies_intr_list
   279              (Library.gen_distinct
   280                 (fn (x, y) => Thm.term_of x = Thm.term_of y)
   281                 cprems) fixedthconcl)
   282       end
   283     else th;
   284 
   285 (* General substiuttion of multiple occurances using one of
   286    the given theorems*)
   287 exception eqsubst_occL_exp of
   288           string * (int list) * (thm list) * int * thm;
   289 fun skip_first_occs_search occ srchf sinfo lhs =
   290     case (IsaPLib.skipto_seqseq occ (srchf sinfo lhs)) of
   291       IsaPLib.skipmore _ => Seq.empty
   292     | IsaPLib.skipseq ss => Seq.flat ss;
   293 
   294 fun eqsubst_tac occL thms i th =
   295     let val nprems = Thm.nprems_of th in
   296       if nprems < i then Seq.empty else
   297       let val thmseq = (Seq.of_list thms)
   298         fun apply_occ occ th =
   299             thmseq :->
   300                     (fn r => eqsubst_tac' (skip_first_occs_search
   301                                     occ searchf_tlr_unify_valid) r
   302                                  (i + ((Thm.nprems_of th) - nprems))
   303                                  th);
   304         val sortedoccL =
   305             Library.sort (Library.rev_order o Library.int_ord) occL;
   306       in
   307         Seq.map distinct_subgoals (Seq.EVERY (map apply_occ sortedoccL) th)
   308       end
   309     end
   310     handle THM _ => raise eqsubst_occL_exp ("THM",occL,thms,i,th);
   311 
   312 
   313 (* inthms are the given arguments in Isar, and treated as eqstep with
   314    the first one, then the second etc *)
   315 fun eqsubst_meth occL inthms =
   316     Method.METHOD
   317       (fn facts =>
   318           HEADGOAL ( Method.insert_tac facts THEN' eqsubst_tac occL inthms ));
   319 
   320 (* apply a substitution inside assumption j, keeps asm in the same place *)
   321 fun apply_subst_in_asm i th rule ((cfvs, j, ngoalprems, pth),m) =
   322     let
   323       val th2 = Thm.rotate_rule (j - 1) i th; (* put premice first *)
   324       val preelimrule =
   325           (RWInst.rw m rule pth)
   326             |> (Seq.hd o Tactic.prune_params_tac)
   327             |> Thm.permute_prems 0 ~1 (* put old asm first *)
   328             |> IsaND.unfix_frees cfvs (* unfix any global params *)
   329             |> RWInst.beta_eta_contract; (* normal form *)
   330   (*    val elimrule =
   331           preelimrule
   332             |> Tactic.make_elim (* make into elim rule *)
   333             |> Thm.lift_rule (th2, i); (* lift into context *)
   334    *)
   335     in
   336       (* ~j because new asm starts at back, thus we subtract 1 *)
   337       Seq.map (Thm.rotate_rule (~j) ((Thm.nprems_of rule) + i))
   338       (Tactic.dtac preelimrule i th2)
   339 
   340       (* (Thm.bicompose
   341                  false (* use unification *)
   342                  (true, (* elim resolution *)
   343                   elimrule, (2 + (Thm.nprems_of rule)) - ngoalprems)
   344                  i th2) *)
   345     end;
   346 
   347 
   348 (* prepare to substitute within the j'th premise of subgoal i of gth,
   349 using a meta-level equation. Note that we assume rule has var indicies
   350 zero'd. Note that we also assume that premt is the j'th premice of
   351 subgoal i of gth. Note the repetition of work done for each
   352 assumption, i.e. this can be made more efficient for search over
   353 multiple assumptions.  *)
   354 fun prep_subst_in_asm i gth j =
   355     let
   356       val th = Thm.incr_indexes 1 gth;
   357       val tgt_term = Thm.prop_of th;
   358 
   359       val sgn = Thm.sign_of_thm th;
   360       val ctermify = Thm.cterm_of sgn;
   361       val trivify = Thm.trivial o ctermify;
   362 
   363       val (fixedbody, fvs) = IsaND.fix_alls_term i tgt_term;
   364       val cfvs = rev (map ctermify fvs);
   365 
   366       val asmt = Library.nth_elem(j - 1,(Logic.strip_imp_prems fixedbody));
   367       val asm_nprems = length (Logic.strip_imp_prems asmt);
   368 
   369       val pth = trivify asmt;
   370       val maxidx = Term.maxidx_of_term asmt;
   371 
   372       val ft = ((IsaFTerm.focus_right
   373                  o IsaFTerm.fcterm_of_term
   374                  o Thm.prop_of) pth)
   375     in ((cfvs, j, asm_nprems, pth), (sgn, maxidx, ft)) end;
   376 
   377 (* prepare subst in every possible assumption *)
   378 fun prep_subst_in_asms i gth =
   379     map (prep_subst_in_asm i gth)
   380         ((rev o IsaPLib.mk_num_list o length)
   381            (Logic.prems_of_goal (Thm.prop_of gth) i));
   382 
   383 
   384 (* substitute in an assumption using an object or meta level equality *)
   385 fun eqsubst_asm_tac' searchf skipocc instepthm i th =
   386     let
   387       val asmpreps = prep_subst_in_asms i th;
   388       val stepthms =
   389           Seq.map Drule.zero_var_indexes
   390               (Seq.of_list (EqRuleData.prep_meta_eq instepthm))
   391       fun rewrite_with_thm r =
   392           let val (lhs,_) = Logic.dest_equals (Thm.concl_of r)
   393             fun occ_search occ [] = Seq.empty
   394               | occ_search occ ((asminfo, searchinfo)::moreasms) =
   395                 (case searchf searchinfo occ lhs of
   396                    IsaPLib.skipmore i => occ_search i moreasms
   397                  | IsaPLib.skipseq ss =>
   398                    Seq.append (Seq.map (Library.pair asminfo)
   399                                        (Seq.flat ss),
   400                                occ_search 1 moreasms))
   401                               (* find later substs also *)
   402           in
   403             (occ_search skipocc asmpreps) :-> (apply_subst_in_asm i th r)
   404           end;
   405     in stepthms :-> rewrite_with_thm end;
   406 
   407 
   408 fun skip_first_asm_occs_search searchf sinfo occ lhs =
   409     IsaPLib.skipto_seqseq occ (searchf sinfo lhs);
   410 
   411 fun eqsubst_asm_tac occL thms i th =
   412     let val nprems = Thm.nprems_of th
   413     in
   414       if nprems < i then Seq.empty else
   415       let val thmseq = (Seq.of_list thms)
   416         fun apply_occ occK th =
   417             thmseq :->
   418                     (fn r =>
   419                         eqsubst_asm_tac' (skip_first_asm_occs_search
   420                                             searchf_tlr_unify_valid) occK r
   421                                          (i + ((Thm.nprems_of th) - nprems))
   422                                          th);
   423         val sortedoccs =
   424             Library.sort (Library.rev_order o Library.int_ord) occL
   425       in
   426         Seq.map distinct_subgoals
   427                 (Seq.EVERY (map apply_occ sortedoccs) th)
   428       end
   429     end
   430     handle THM _ => raise eqsubst_occL_exp ("THM",occL,thms,i,th);
   431 
   432 (* inthms are the given arguments in Isar, and treated as eqstep with
   433    the first one, then the second etc *)
   434 fun eqsubst_asm_meth occL inthms =
   435     Method.METHOD
   436       (fn facts =>
   437           HEADGOAL (Method.insert_tac facts THEN' eqsubst_asm_tac occL inthms ));
   438 
   439 (* combination method that takes a flag (true indicates that subst
   440 should be done to an assumption, false = apply to the conclusion of
   441 the goal) as well as the theorems to use *)
   442 fun meth ((asmflag, occL), inthms) ctxt =
   443     if asmflag then eqsubst_asm_meth occL inthms else eqsubst_meth occL inthms;
   444 
   445 (* syntax for options, given "(asm)" will give back true, without
   446    gives back false *)
   447 val options_syntax =
   448     (Args.parens (Args.$$$ "asm") >> (K true)) ||
   449      (Scan.succeed false);
   450 
   451 val ith_syntax =
   452     (Args.parens (Scan.repeat Args.nat))
   453       || (Scan.succeed [0]);
   454 
   455 (* method syntax, first take options, then theorems *)
   456 fun meth_syntax meth src ctxt =
   457     meth (snd (Method.syntax ((Scan.lift options_syntax)
   458                                 -- (Scan.lift ith_syntax)
   459                                 -- Attrib.local_thms) src ctxt))
   460          ctxt;
   461 
   462 (* setup function for adding method to theory. *)
   463 val setup =
   464     [Method.add_method ("subst", meth_syntax meth, "Substiution with an equation. Use \"(asm)\" option to substitute in an assumption.")];
   465 
   466 end;