src/Tools/eqsubst.ML
author wenzelm
Sat, 28 Feb 2009 14:02:12 +0100
changeset 30160 5f7b17941730
parent 29269 src/Provers/eqsubst.ML@5c25a2012975
child 30321 3d03190d2864
permissions -rw-r--r--
moved some generic tools to src/Tools/ -- src/Provers is essentially obsolete;
wenzelm@30160
     1
(*  Title:      Tools/eqsubst.ML
wenzelm@29269
     2
    Author:     Lucas Dixon, University of Edinburgh
wenzelm@18598
     3
wenzelm@18598
     4
A proof method to perform a substiution using an equation.
paulson@15481
     5
*)
paulson@15481
     6
wenzelm@18591
     7
signature EQSUBST =
paulson@15481
     8
sig
wenzelm@29269
     9
  (* a type abbreviation for match information *)
dixon@19871
    10
  type match =
dixon@19871
    11
       ((indexname * (sort * typ)) list (* type instantiations *)
dixon@19871
    12
        * (indexname * (typ * term)) list) (* term instantiations *)
dixon@19871
    13
       * (string * typ) list (* fake named type abs env *)
dixon@19871
    14
       * (string * typ) list (* type abs env *)
dixon@19871
    15
       * term (* outer term *)
dixon@19871
    16
dixon@19871
    17
  type searchinfo =
dixon@19871
    18
       theory
dixon@19871
    19
       * int (* maxidx *)
dixon@19871
    20
       * Zipper.T (* focusterm to search under *)
dixon@19871
    21
dixon@19871
    22
    exception eqsubst_occL_exp of
dixon@19871
    23
       string * int list * Thm.thm list * int * Thm.thm
dixon@19871
    24
    
dixon@19871
    25
    (* low level substitution functions *)
dixon@19871
    26
    val apply_subst_in_asm :
dixon@19871
    27
       int ->
dixon@19871
    28
       Thm.thm ->
dixon@19871
    29
       Thm.thm ->
dixon@19871
    30
       (Thm.cterm list * int * 'a * Thm.thm) * match -> Thm.thm Seq.seq
dixon@19871
    31
    val apply_subst_in_concl :
dixon@19871
    32
       int ->
dixon@19871
    33
       Thm.thm ->
dixon@19871
    34
       Thm.cterm list * Thm.thm ->
dixon@19871
    35
       Thm.thm -> match -> Thm.thm Seq.seq
dixon@19871
    36
dixon@19871
    37
    (* matching/unification within zippers *)
dixon@19871
    38
    val clean_match_z :
dixon@19871
    39
       Context.theory -> Term.term -> Zipper.T -> match option
dixon@19871
    40
    val clean_unify_z :
dixon@19871
    41
       Context.theory -> int -> Term.term -> Zipper.T -> match Seq.seq
dixon@19871
    42
dixon@19871
    43
    (* skipping things in seq seq's *)
dixon@19871
    44
dixon@19871
    45
   (* skipping non-empty sub-sequences but when we reach the end
dixon@19871
    46
      of the seq, remembering how much we have left to skip. *)
dixon@19871
    47
    datatype 'a skipseq = SkipMore of int
dixon@19871
    48
      | SkipSeq of 'a Seq.seq Seq.seq;
dixon@19871
    49
dixon@19871
    50
    val skip_first_asm_occs_search :
dixon@19871
    51
       ('a -> 'b -> 'c Seq.seq Seq.seq) ->
dixon@19871
    52
       'a -> int -> 'b -> 'c skipseq
dixon@19871
    53
    val skip_first_occs_search :
dixon@19871
    54
       int -> ('a -> 'b -> 'c Seq.seq Seq.seq) -> 'a -> 'b -> 'c Seq.seq
dixon@19871
    55
    val skipto_skipseq : int -> 'a Seq.seq Seq.seq -> 'a skipseq
dixon@19871
    56
dixon@19871
    57
    (* tactics *)
dixon@19871
    58
    val eqsubst_asm_tac :
dixon@19871
    59
       Proof.context ->
dixon@19871
    60
       int list -> Thm.thm list -> int -> Thm.thm -> Thm.thm Seq.seq
dixon@19871
    61
    val eqsubst_asm_tac' :
dixon@19871
    62
       Proof.context ->
dixon@19871
    63
       (searchinfo -> int -> Term.term -> match skipseq) ->
dixon@19871
    64
       int -> Thm.thm -> int -> Thm.thm -> Thm.thm Seq.seq
dixon@19871
    65
    val eqsubst_tac :
dixon@19871
    66
       Proof.context ->
dixon@22727
    67
       int list -> (* list of occurences to rewrite, use [0] for any *)
dixon@22727
    68
       Thm.thm list -> int -> Thm.thm -> Thm.thm Seq.seq
dixon@19871
    69
    val eqsubst_tac' :
dixon@22727
    70
       Proof.context -> (* proof context *)
dixon@22727
    71
       (searchinfo -> Term.term -> match Seq.seq) (* search function *)
dixon@22727
    72
       -> Thm.thm (* equation theorem to rewrite with *)
dixon@22727
    73
       -> int (* subgoal number in goal theorem *)
dixon@22727
    74
       -> Thm.thm (* goal theorem *)
dixon@22727
    75
       -> Thm.thm Seq.seq (* rewritten goal theorem *)
dixon@19871
    76
dixon@19871
    77
dixon@19871
    78
    val fakefree_badbounds :
dixon@19871
    79
       (string * Term.typ) list ->
dixon@19871
    80
       Term.term ->
dixon@19871
    81
       (string * Term.typ) list * (string * Term.typ) list * Term.term
dixon@19871
    82
dixon@19871
    83
    val mk_foo_match :
dixon@19871
    84
       (Term.term -> Term.term) ->
dixon@19871
    85
       ('a * Term.typ) list -> Term.term -> Term.term
dixon@19871
    86
dixon@19871
    87
    (* preparing substitution *)
dixon@19871
    88
    val prep_meta_eq : Proof.context -> Thm.thm -> Thm.thm list
dixon@19871
    89
    val prep_concl_subst :
dixon@19871
    90
       int -> Thm.thm -> (Thm.cterm list * Thm.thm) * searchinfo
dixon@19871
    91
    val prep_subst_in_asm :
dixon@19871
    92
       int -> Thm.thm -> int ->
dixon@19871
    93
       (Thm.cterm list * int * int * Thm.thm) * searchinfo
dixon@19871
    94
    val prep_subst_in_asms :
dixon@19871
    95
       int -> Thm.thm ->
dixon@19871
    96
       ((Thm.cterm list * int * int * Thm.thm) * searchinfo) list
dixon@19871
    97
    val prep_zipper_match :
dixon@19871
    98
       Zipper.T -> Term.term * ((string * Term.typ) list * (string * Term.typ) list * Term.term)
dixon@19871
    99
dixon@19871
   100
    (* search for substitutions *)
dixon@19871
   101
    val valid_match_start : Zipper.T -> bool
dixon@19871
   102
    val search_lr_all : Zipper.T -> Zipper.T Seq.seq
dixon@19871
   103
    val search_lr_valid : (Zipper.T -> bool) -> Zipper.T -> Zipper.T Seq.seq
dixon@19871
   104
    val searchf_lr_unify_all :
dixon@19871
   105
       searchinfo -> Term.term -> match Seq.seq Seq.seq
dixon@19871
   106
    val searchf_lr_unify_valid :
dixon@19871
   107
       searchinfo -> Term.term -> match Seq.seq Seq.seq
narboux@23064
   108
    val searchf_bt_unify_valid :
narboux@23064
   109
       searchinfo -> Term.term -> match Seq.seq Seq.seq
dixon@19871
   110
dixon@19871
   111
    (* syntax tools *)
dixon@19871
   112
    val ith_syntax : Args.T list -> int list * Args.T list
dixon@19871
   113
    val options_syntax : Args.T list -> bool * Args.T list
dixon@19871
   114
dixon@19871
   115
    (* Isar level hooks *)
wenzelm@20289
   116
    val eqsubst_asm_meth : Proof.context -> int list -> Thm.thm list -> Proof.method
wenzelm@20289
   117
    val eqsubst_meth : Proof.context -> int list -> Thm.thm list -> Proof.method
wenzelm@20289
   118
    val subst_meth : Method.src -> Proof.context -> Proof.method
dixon@19871
   119
    val setup : theory -> theory
dixon@19871
   120
paulson@15481
   121
end;
paulson@15481
   122
dixon@19835
   123
structure EqSubst
dixon@19871
   124
: EQSUBST
dixon@19835
   125
= struct
dixon@16004
   126
dixon@19835
   127
structure Z = Zipper;
dixon@19835
   128
dixon@19835
   129
(* changes object "=" to meta "==" which prepares a given rewrite rule *)
wenzelm@18598
   130
fun prep_meta_eq ctxt =
wenzelm@18598
   131
  let val (_, {mk_rews = {mk, ...}, ...}) = Simplifier.rep_ss (Simplifier.local_simpset_of ctxt)
wenzelm@18598
   132
  in mk #> map Drule.zero_var_indexes end;
wenzelm@18598
   133
paulson@15481
   134
dixon@15915
   135
  (* a type abriviation for match information *)
wenzelm@16978
   136
  type match =
wenzelm@16978
   137
       ((indexname * (sort * typ)) list (* type instantiations *)
wenzelm@16978
   138
        * (indexname * (typ * term)) list) (* term instantiations *)
wenzelm@16978
   139
       * (string * typ) list (* fake named type abs env *)
wenzelm@16978
   140
       * (string * typ) list (* type abs env *)
wenzelm@16978
   141
       * term (* outer term *)
dixon@15550
   142
wenzelm@16978
   143
  type searchinfo =
wenzelm@18598
   144
       theory
dixon@16004
   145
       * int (* maxidx *)
dixon@19835
   146
       * Zipper.T (* focusterm to search under *)
dixon@19835
   147
dixon@19835
   148
dixon@19835
   149
(* skipping non-empty sub-sequences but when we reach the end
dixon@19835
   150
   of the seq, remembering how much we have left to skip. *)
dixon@19835
   151
datatype 'a skipseq = SkipMore of int
dixon@19835
   152
  | SkipSeq of 'a Seq.seq Seq.seq;
dixon@19835
   153
(* given a seqseq, skip the first m non-empty seq's, note deficit *)
dixon@19835
   154
fun skipto_skipseq m s = 
dixon@19835
   155
    let 
dixon@19835
   156
      fun skip_occs n sq = 
dixon@19835
   157
          case Seq.pull sq of 
dixon@19835
   158
            NONE => SkipMore n
dixon@19835
   159
          | SOME (h,t) => 
dixon@19835
   160
            (case Seq.pull h of NONE => skip_occs n t
dixon@19835
   161
             | SOME _ => if n <= 1 then SkipSeq (Seq.cons h t)
dixon@19835
   162
                         else skip_occs (n - 1) t)
dixon@19835
   163
    in (skip_occs m s) end;
dixon@19835
   164
dixon@19835
   165
(* note: outerterm is the taget with the match replaced by a bound 
dixon@19835
   166
         variable : ie: "P lhs" beocmes "%x. P x" 
dixon@19835
   167
         insts is the types of instantiations of vars in lhs
dixon@19835
   168
         and typinsts is the type instantiations of types in the lhs
dixon@19835
   169
         Note: Final rule is the rule lifted into the ontext of the 
dixon@19835
   170
         taget thm. *)
dixon@19835
   171
fun mk_foo_match mkuptermfunc Ts t = 
dixon@19835
   172
    let 
dixon@19835
   173
      val ty = Term.type_of t
dixon@19835
   174
      val bigtype = (rev (map snd Ts)) ---> ty
dixon@19835
   175
      fun mk_foo 0 t = t
dixon@19835
   176
        | mk_foo i t = mk_foo (i - 1) (t $ (Bound (i - 1)))
dixon@19835
   177
      val num_of_bnds = (length Ts)
dixon@19835
   178
      (* foo_term = "fooabs y0 ... yn" where y's are local bounds *)
dixon@19835
   179
      val foo_term = mk_foo num_of_bnds (Bound num_of_bnds)
dixon@19835
   180
    in Abs("fooabs", bigtype, mkuptermfunc foo_term) end;
dixon@19835
   181
dixon@19835
   182
(* T is outer bound vars, n is number of locally bound vars *)
dixon@19835
   183
(* THINK: is order of Ts correct...? or reversed? *)
dixon@19835
   184
fun fakefree_badbounds Ts t = 
dixon@19835
   185
    let val (FakeTs,Ts,newnames) = 
dixon@19835
   186
            List.foldr (fn ((n,ty),(FakeTs,Ts,usednames)) => 
wenzelm@20071
   187
                           let val newname = Name.variant usednames n
dixon@19835
   188
                           in ((RWTools.mk_fake_bound_name newname,ty)::FakeTs,
dixon@19835
   189
                               (newname,ty)::Ts, 
dixon@19835
   190
                               newname::usednames) end)
dixon@19835
   191
                       ([],[],[])
dixon@19835
   192
                       Ts
dixon@19835
   193
    in (FakeTs, Ts, Term.subst_bounds (map Free FakeTs, t)) end;
dixon@19835
   194
dixon@19835
   195
(* before matching we need to fake the bound vars that are missing an
dixon@19835
   196
abstraction. In this function we additionally construct the
dixon@19835
   197
abstraction environment, and an outer context term (with the focus
dixon@19835
   198
abstracted out) for use in rewriting with RWInst.rw *)
dixon@19835
   199
fun prep_zipper_match z = 
dixon@19835
   200
    let 
dixon@19835
   201
      val t = Z.trm z  
dixon@19835
   202
      val c = Z.ctxt z
dixon@19835
   203
      val Ts = Z.C.nty_ctxt c
dixon@19835
   204
      val (FakeTs', Ts', t') = fakefree_badbounds Ts t
dixon@19835
   205
      val absterm = mk_foo_match (Z.C.apply c) Ts' t'
dixon@19835
   206
    in
dixon@19835
   207
      (t', (FakeTs', Ts', absterm))
dixon@19835
   208
    end;
dixon@19835
   209
dixon@19835
   210
(* Matching and Unification with exception handled *)
dixon@19835
   211
fun clean_match thy (a as (pat, t)) =
dixon@19835
   212
  let val (tyenv, tenv) = Pattern.match thy a (Vartab.empty, Vartab.empty)
dixon@19835
   213
  in SOME (Vartab.dest tyenv, Vartab.dest tenv)
dixon@19835
   214
  end handle Pattern.MATCH => NONE;
dixon@27033
   215
dixon@19835
   216
(* given theory, max var index, pat, tgt; returns Seq of instantiations *)
dixon@27033
   217
fun clean_unify thry ix (a as (pat, tgt)) =
dixon@19835
   218
    let
dixon@19835
   219
      (* type info will be re-derived, maybe this can be cached
dixon@19835
   220
         for efficiency? *)
dixon@19835
   221
      val pat_ty = Term.type_of pat;
dixon@19835
   222
      val tgt_ty = Term.type_of tgt;
dixon@19835
   223
      (* is it OK to ignore the type instantiation info?
dixon@19835
   224
         or should I be using it? *)
dixon@19835
   225
      val typs_unify =
wenzelm@29269
   226
          SOME (Sign.typ_unify thry (pat_ty, tgt_ty) (Vartab.empty, ix))
dixon@19835
   227
            handle Type.TUNIFY => NONE;
dixon@19835
   228
    in
dixon@19835
   229
      case typs_unify of
dixon@19835
   230
        SOME (typinsttab, ix2) =>
dixon@19835
   231
        let
dixon@19835
   232
      (* is it right to throw away the flexes?
dixon@19835
   233
         or should I be using them somehow? *)
dixon@19835
   234
          fun mk_insts env =
dixon@19835
   235
            (Vartab.dest (Envir.type_env env),
dixon@19835
   236
             Envir.alist_of env);
dixon@19835
   237
          val initenv = Envir.Envir {asol = Vartab.empty,
dixon@19835
   238
                                     iTs = typinsttab, maxidx = ix2};
dixon@27033
   239
          val useq = Unify.smash_unifiers thry [a] initenv
dixon@19835
   240
	            handle UnequalLengths => Seq.empty
dixon@19835
   241
		               | Term.TERM _ => Seq.empty;
dixon@19835
   242
          fun clean_unify' useq () =
dixon@19835
   243
              (case (Seq.pull useq) of
dixon@19835
   244
                 NONE => NONE
dixon@19835
   245
               | SOME (h,t) => SOME (mk_insts h, Seq.make (clean_unify' t)))
dixon@27033
   246
	            handle UnequalLengths => NONE
dixon@27033
   247
                   | Term.TERM _ => NONE
dixon@19835
   248
        in
dixon@19835
   249
          (Seq.make (clean_unify' useq))
dixon@19835
   250
        end
dixon@19835
   251
      | NONE => Seq.empty
dixon@19835
   252
    end;
dixon@19835
   253
dixon@19835
   254
(* Matching and Unification for zippers *)
dixon@19835
   255
(* Note: Ts is a modified version of the original names of the outer
dixon@19835
   256
bound variables. New names have been introduced to make sure they are
dixon@19835
   257
unique w.r.t all names in the term and each other. usednames' is
dixon@19835
   258
oldnames + new names. *)
dixon@19835
   259
fun clean_match_z thy pat z = 
dixon@19835
   260
    let val (t, (FakeTs,Ts,absterm)) = prep_zipper_match z in
dixon@19835
   261
      case clean_match thy (pat, t) of 
dixon@19835
   262
        NONE => NONE 
dixon@19835
   263
      | SOME insts => SOME (insts, FakeTs, Ts, absterm) end;
dixon@19835
   264
(* ix = max var index *)
dixon@19835
   265
fun clean_unify_z sgn ix pat z = 
dixon@19835
   266
    let val (t, (FakeTs, Ts,absterm)) = prep_zipper_match z in
dixon@19835
   267
    Seq.map (fn insts => (insts, FakeTs, Ts, absterm)) 
dixon@19835
   268
            (clean_unify sgn ix (t, pat)) end;
dixon@19835
   269
dixon@15550
   270
dixon@15538
   271
(* FOR DEBUGGING...
dixon@15538
   272
type trace_subst_errT = int (* subgoal *)
wenzelm@16978
   273
        * thm (* thm with all goals *)
dixon@15538
   274
        * (Thm.cterm list (* certified free var placeholders for vars *)
wenzelm@16978
   275
           * thm)  (* trivial thm of goal concl *)
dixon@15538
   276
            (* possible matches/unifiers *)
wenzelm@16978
   277
        * thm (* rule *)
wenzelm@16978
   278
        * (((indexname * typ) list (* type instantiations *)
wenzelm@16978
   279
              * (indexname * term) list ) (* term instantiations *)
wenzelm@16978
   280
             * (string * typ) list (* Type abs env *)
wenzelm@16978
   281
             * term) (* outer term *);
dixon@15538
   282
dixon@15538
   283
val trace_subst_err = (ref NONE : trace_subst_errT option ref);
dixon@15538
   284
val trace_subst_search = ref false;
dixon@15538
   285
exception trace_subst_exp of trace_subst_errT;
dixon@19835
   286
*)
dixon@19835
   287
dixon@19835
   288
dixon@19835
   289
fun bot_left_leaf_of (l $ r) = bot_left_leaf_of l
dixon@19835
   290
  | bot_left_leaf_of (Abs(s,ty,t)) = bot_left_leaf_of t
dixon@19835
   291
  | bot_left_leaf_of x = x;
dixon@19835
   292
dixon@19975
   293
(* Avoid considering replacing terms which have a var at the head as
dixon@19975
   294
   they always succeed trivially, and uninterestingly. *)
dixon@19835
   295
fun valid_match_start z =
dixon@19835
   296
    (case bot_left_leaf_of (Z.trm z) of 
dixon@19975
   297
      Var _ => false 
dixon@19975
   298
      | _ => true);
dixon@19975
   299
dixon@19835
   300
(* search from top, left to right, then down *)
dixon@19871
   301
val search_lr_all = ZipperSearch.all_bl_ur;
dixon@15538
   302
dixon@15814
   303
(* search from top, left to right, then down *)
dixon@19871
   304
fun search_lr_valid validf =
dixon@19835
   305
    let 
dixon@19835
   306
      fun sf_valid_td_lr z = 
dixon@19835
   307
          let val here = if validf z then [Z.Here z] else [] in
dixon@19835
   308
            case Z.trm z 
dixon@19871
   309
             of _ $ _ => [Z.LookIn (Z.move_down_left z)] 
dixon@19871
   310
                         @ here 
dixon@19871
   311
                         @ [Z.LookIn (Z.move_down_right z)]
dixon@19835
   312
              | Abs _ => here @ [Z.LookIn (Z.move_down_abs z)]
dixon@19835
   313
              | _ => here
dixon@19835
   314
          end;
dixon@19835
   315
    in Z.lzy_search sf_valid_td_lr end;
dixon@15814
   316
narboux@23064
   317
(* search from bottom to top, left to right *)
narboux@23064
   318
narboux@23064
   319
fun search_bt_valid validf =
narboux@23064
   320
    let 
narboux@23064
   321
      fun sf_valid_td_lr z = 
narboux@23064
   322
          let val here = if validf z then [Z.Here z] else [] in
narboux@23064
   323
            case Z.trm z 
narboux@23064
   324
             of _ $ _ => [Z.LookIn (Z.move_down_left z), 
narboux@23064
   325
                          Z.LookIn (Z.move_down_right z)] @ here
narboux@23064
   326
              | Abs _ => [Z.LookIn (Z.move_down_abs z)] @ here
narboux@23064
   327
              | _ => here
narboux@23064
   328
          end;
narboux@23064
   329
    in Z.lzy_search sf_valid_td_lr end;
narboux@23064
   330
narboux@23064
   331
fun searchf_unify_gen f (sgn, maxidx, z) lhs =
narboux@23064
   332
    Seq.map (clean_unify_z sgn maxidx lhs) 
narboux@23064
   333
            (Z.limit_apply f z);
narboux@23064
   334
dixon@15814
   335
(* search all unifications *)
narboux@23064
   336
val searchf_lr_unify_all =
narboux@23064
   337
    searchf_unify_gen search_lr_all;
paulson@15481
   338
dixon@15814
   339
(* search only for 'valid' unifiers (non abs subterms and non vars) *)
narboux@23064
   340
val searchf_lr_unify_valid = 
narboux@23064
   341
    searchf_unify_gen (search_lr_valid valid_match_start);
dixon@15929
   342
narboux@23064
   343
val searchf_bt_unify_valid =
narboux@23064
   344
    searchf_unify_gen (search_bt_valid valid_match_start);
dixon@15814
   345
dixon@15538
   346
(* apply a substitution in the conclusion of the theorem th *)
dixon@15538
   347
(* cfvs are certified free var placeholders for goal params *)
dixon@15538
   348
(* conclthm is a theorem of for just the conclusion *)
dixon@15538
   349
(* m is instantiation/match information *)
dixon@15538
   350
(* rule is the equation for substitution *)
wenzelm@16978
   351
fun apply_subst_in_concl i th (cfvs, conclthm) rule m =
dixon@15538
   352
    (RWInst.rw m rule conclthm)
dixon@15855
   353
      |> IsaND.unfix_frees cfvs
dixon@15915
   354
      |> RWInst.beta_eta_contract
dixon@15538
   355
      |> (fn r => Tactic.rtac r i th);
paulson@15481
   356
paulson@15481
   357
(* substitute within the conclusion of goal i of gth, using a meta
dixon@15538
   358
equation rule. Note that we assume rule has var indicies zero'd *)
wenzelm@16978
   359
fun prep_concl_subst i gth =
wenzelm@16978
   360
    let
paulson@15481
   361
      val th = Thm.incr_indexes 1 gth;
paulson@15481
   362
      val tgt_term = Thm.prop_of th;
paulson@15481
   363
wenzelm@22578
   364
      val sgn = Thm.theory_of_thm th;
paulson@15481
   365
      val ctermify = Thm.cterm_of sgn;
paulson@15481
   366
      val trivify = Thm.trivial o ctermify;
paulson@15481
   367
paulson@15481
   368
      val (fixedbody, fvs) = IsaND.fix_alls_term i tgt_term;
paulson@15481
   369
      val cfvs = rev (map ctermify fvs);
paulson@15481
   370
dixon@15538
   371
      val conclterm = Logic.strip_imp_concl fixedbody;
dixon@15538
   372
      val conclthm = trivify conclterm;
dixon@27033
   373
      val maxidx = Thm.maxidx_of th;
dixon@19835
   374
      val ft = ((Z.move_down_right (* ==> *)
dixon@19835
   375
                 o Z.move_down_left (* Trueprop *)
dixon@19835
   376
                 o Z.mktop
dixon@16004
   377
                 o Thm.prop_of) conclthm)
paulson@15481
   378
    in
dixon@16004
   379
      ((cfvs, conclthm), (sgn, maxidx, ft))
paulson@15481
   380
    end;
paulson@15481
   381
paulson@15481
   382
(* substitute using an object or meta level equality *)
wenzelm@18598
   383
fun eqsubst_tac' ctxt searchf instepthm i th =
wenzelm@16978
   384
    let
dixon@16004
   385
      val (cvfsconclthm, searchinfo) = prep_concl_subst i th;
wenzelm@18598
   386
      val stepthms = Seq.of_list (prep_meta_eq ctxt instepthm);
dixon@15538
   387
      fun rewrite_with_thm r =
dixon@15538
   388
          let val (lhs,_) = Logic.dest_equals (Thm.concl_of r);
wenzelm@18598
   389
          in searchf searchinfo lhs
wenzelm@18598
   390
             |> Seq.maps (apply_subst_in_concl i th cvfsconclthm r) end;
wenzelm@18598
   391
    in stepthms |> Seq.maps rewrite_with_thm end;
dixon@15538
   392
dixon@15538
   393
wenzelm@19047
   394
(* distinct subgoals *)
wenzelm@19047
   395
fun distinct_subgoals th =
wenzelm@19047
   396
  the_default th (SINGLE distinct_subgoals_tac th);
dixon@15959
   397
wenzelm@19047
   398
(* General substitution of multiple occurances using one of
dixon@15936
   399
   the given theorems*)
dixon@19835
   400
dixon@19835
   401
wenzelm@16978
   402
exception eqsubst_occL_exp of
wenzelm@16978
   403
          string * (int list) * (thm list) * int * thm;
wenzelm@16978
   404
fun skip_first_occs_search occ srchf sinfo lhs =
dixon@19835
   405
    case (skipto_skipseq occ (srchf sinfo lhs)) of
dixon@19835
   406
      SkipMore _ => Seq.empty
dixon@19835
   407
    | SkipSeq ss => Seq.flat ss;
dixon@16004
   408
dixon@22727
   409
(* The occL is a list of integers indicating which occurence
dixon@22727
   410
w.r.t. the search order, to rewrite. Backtracking will also find later
dixon@22727
   411
occurences, but all earlier ones are skipped. Thus you can use [0] to
dixon@22727
   412
just find all rewrites. *)
dixon@22727
   413
wenzelm@18598
   414
fun eqsubst_tac ctxt occL thms i th =
dixon@15936
   415
    let val nprems = Thm.nprems_of th in
dixon@15936
   416
      if nprems < i then Seq.empty else
wenzelm@16978
   417
      let val thmseq = (Seq.of_list thms)
wenzelm@16978
   418
        fun apply_occ occ th =
wenzelm@18598
   419
            thmseq |> Seq.maps
dixon@19835
   420
                    (fn r => eqsubst_tac' 
dixon@19835
   421
                               ctxt 
dixon@19835
   422
                               (skip_first_occs_search
dixon@19871
   423
                                  occ searchf_lr_unify_valid) r
dixon@15936
   424
                                 (i + ((Thm.nprems_of th) - nprems))
dixon@15936
   425
                                 th);
wenzelm@16978
   426
        val sortedoccL =
dixon@16004
   427
            Library.sort (Library.rev_order o Library.int_ord) occL;
dixon@15936
   428
      in
dixon@16004
   429
        Seq.map distinct_subgoals (Seq.EVERY (map apply_occ sortedoccL) th)
dixon@15936
   430
      end
dixon@15959
   431
    end
dixon@15959
   432
    handle THM _ => raise eqsubst_occL_exp ("THM",occL,thms,i,th);
dixon@15959
   433
paulson@15481
   434
paulson@15481
   435
(* inthms are the given arguments in Isar, and treated as eqstep with
paulson@15481
   436
   the first one, then the second etc *)
wenzelm@18598
   437
fun eqsubst_meth ctxt occL inthms =
wenzelm@21588
   438
    Method.SIMPLE_METHOD' (eqsubst_tac ctxt occL inthms);
paulson@15481
   439
dixon@16004
   440
(* apply a substitution inside assumption j, keeps asm in the same place *)
wenzelm@16978
   441
fun apply_subst_in_asm i th rule ((cfvs, j, ngoalprems, pth),m) =
wenzelm@16978
   442
    let
dixon@16004
   443
      val th2 = Thm.rotate_rule (j - 1) i th; (* put premice first *)
wenzelm@16978
   444
      val preelimrule =
dixon@16004
   445
          (RWInst.rw m rule pth)
wenzelm@21708
   446
            |> (Seq.hd o prune_params_tac)
dixon@16004
   447
            |> Thm.permute_prems 0 ~1 (* put old asm first *)
dixon@16004
   448
            |> IsaND.unfix_frees cfvs (* unfix any global params *)
dixon@16004
   449
            |> RWInst.beta_eta_contract; (* normal form *)
wenzelm@16978
   450
  (*    val elimrule =
dixon@16004
   451
          preelimrule
dixon@16004
   452
            |> Tactic.make_elim (* make into elim rule *)
dixon@16004
   453
            |> Thm.lift_rule (th2, i); (* lift into context *)
dixon@16007
   454
   *)
dixon@16004
   455
    in
dixon@16004
   456
      (* ~j because new asm starts at back, thus we subtract 1 *)
dixon@16007
   457
      Seq.map (Thm.rotate_rule (~j) ((Thm.nprems_of rule) + i))
dixon@16007
   458
      (Tactic.dtac preelimrule i th2)
dixon@16007
   459
wenzelm@16978
   460
      (* (Thm.bicompose
dixon@16004
   461
                 false (* use unification *)
dixon@16004
   462
                 (true, (* elim resolution *)
dixon@16007
   463
                  elimrule, (2 + (Thm.nprems_of rule)) - ngoalprems)
dixon@16007
   464
                 i th2) *)
dixon@16004
   465
    end;
dixon@15538
   466
dixon@15538
   467
dixon@15538
   468
(* prepare to substitute within the j'th premise of subgoal i of gth,
dixon@15538
   469
using a meta-level equation. Note that we assume rule has var indicies
dixon@15538
   470
zero'd. Note that we also assume that premt is the j'th premice of
dixon@15538
   471
subgoal i of gth. Note the repetition of work done for each
dixon@15538
   472
assumption, i.e. this can be made more efficient for search over
dixon@15538
   473
multiple assumptions.  *)
wenzelm@16978
   474
fun prep_subst_in_asm i gth j =
wenzelm@16978
   475
    let
paulson@15481
   476
      val th = Thm.incr_indexes 1 gth;
paulson@15481
   477
      val tgt_term = Thm.prop_of th;
paulson@15481
   478
wenzelm@22578
   479
      val sgn = Thm.theory_of_thm th;
paulson@15481
   480
      val ctermify = Thm.cterm_of sgn;
paulson@15481
   481
      val trivify = Thm.trivial o ctermify;
paulson@15481
   482
paulson@15481
   483
      val (fixedbody, fvs) = IsaND.fix_alls_term i tgt_term;
paulson@15481
   484
      val cfvs = rev (map ctermify fvs);
paulson@15481
   485
haftmann@18011
   486
      val asmt = nth (Logic.strip_imp_prems fixedbody) (j - 1);
dixon@15538
   487
      val asm_nprems = length (Logic.strip_imp_prems asmt);
dixon@15538
   488
dixon@15538
   489
      val pth = trivify asmt;
dixon@27033
   490
      val maxidx = Thm.maxidx_of th;
dixon@15538
   491
dixon@19835
   492
      val ft = ((Z.move_down_right (* trueprop *)
dixon@19835
   493
                 o Z.mktop
dixon@16004
   494
                 o Thm.prop_of) pth)
dixon@16004
   495
    in ((cfvs, j, asm_nprems, pth), (sgn, maxidx, ft)) end;
paulson@15481
   496
dixon@15538
   497
(* prepare subst in every possible assumption *)
wenzelm@16978
   498
fun prep_subst_in_asms i gth =
dixon@16004
   499
    map (prep_subst_in_asm i gth)
dixon@19835
   500
        ((fn l => Library.upto (1, length l))
dixon@16004
   501
           (Logic.prems_of_goal (Thm.prop_of gth) i));
dixon@15538
   502
dixon@15538
   503
dixon@15538
   504
(* substitute in an assumption using an object or meta level equality *)
wenzelm@18598
   505
fun eqsubst_asm_tac' ctxt searchf skipocc instepthm i th =
wenzelm@16978
   506
    let
dixon@16004
   507
      val asmpreps = prep_subst_in_asms i th;
wenzelm@18598
   508
      val stepthms = Seq.of_list (prep_meta_eq ctxt instepthm);
dixon@16004
   509
      fun rewrite_with_thm r =
dixon@16004
   510
          let val (lhs,_) = Logic.dest_equals (Thm.concl_of r)
dixon@16004
   511
            fun occ_search occ [] = Seq.empty
dixon@16004
   512
              | occ_search occ ((asminfo, searchinfo)::moreasms) =
wenzelm@16978
   513
                (case searchf searchinfo occ lhs of
dixon@19835
   514
                   SkipMore i => occ_search i moreasms
dixon@19835
   515
                 | SkipSeq ss =>
wenzelm@19861
   516
                   Seq.append (Seq.map (Library.pair asminfo) (Seq.flat ss))
wenzelm@19861
   517
                               (occ_search 1 moreasms))
dixon@16004
   518
                              (* find later substs also *)
wenzelm@16978
   519
          in
wenzelm@18598
   520
            occ_search skipocc asmpreps |> Seq.maps (apply_subst_in_asm i th r)
dixon@16004
   521
          end;
wenzelm@18598
   522
    in stepthms |> Seq.maps rewrite_with_thm end;
dixon@15538
   523
dixon@16004
   524
wenzelm@16978
   525
fun skip_first_asm_occs_search searchf sinfo occ lhs =
dixon@19835
   526
    skipto_skipseq occ (searchf sinfo lhs);
dixon@16004
   527
wenzelm@18598
   528
fun eqsubst_asm_tac ctxt occL thms i th =
wenzelm@16978
   529
    let val nprems = Thm.nprems_of th
dixon@15538
   530
    in
dixon@16004
   531
      if nprems < i then Seq.empty else
wenzelm@16978
   532
      let val thmseq = (Seq.of_list thms)
wenzelm@16978
   533
        fun apply_occ occK th =
wenzelm@18598
   534
            thmseq |> Seq.maps
wenzelm@16978
   535
                    (fn r =>
wenzelm@18598
   536
                        eqsubst_asm_tac' ctxt (skip_first_asm_occs_search
dixon@19871
   537
                                            searchf_lr_unify_valid) occK r
dixon@16004
   538
                                         (i + ((Thm.nprems_of th) - nprems))
dixon@16004
   539
                                         th);
wenzelm@16978
   540
        val sortedoccs =
dixon@16004
   541
            Library.sort (Library.rev_order o Library.int_ord) occL
dixon@16004
   542
      in
dixon@16004
   543
        Seq.map distinct_subgoals
dixon@16004
   544
                (Seq.EVERY (map apply_occ sortedoccs) th)
dixon@16004
   545
      end
dixon@16004
   546
    end
dixon@16004
   547
    handle THM _ => raise eqsubst_occL_exp ("THM",occL,thms,i,th);
paulson@15481
   548
paulson@15481
   549
(* inthms are the given arguments in Isar, and treated as eqstep with
paulson@15481
   550
   the first one, then the second etc *)
wenzelm@18598
   551
fun eqsubst_asm_meth ctxt occL inthms =
wenzelm@21588
   552
    Method.SIMPLE_METHOD' (eqsubst_asm_tac ctxt occL inthms);
paulson@15481
   553
paulson@15481
   554
(* syntax for options, given "(asm)" will give back true, without
paulson@15481
   555
   gives back false *)
paulson@15481
   556
val options_syntax =
paulson@15481
   557
    (Args.parens (Args.$$$ "asm") >> (K true)) ||
paulson@15481
   558
     (Scan.succeed false);
dixon@15936
   559
dixon@15929
   560
val ith_syntax =
wenzelm@27809
   561
    Scan.optional (Args.parens (Scan.repeat OuterParse.nat)) [0];
paulson@15481
   562
wenzelm@18598
   563
(* combination method that takes a flag (true indicates that subst
wenzelm@18598
   564
should be done to an assumption, false = apply to the conclusion of
wenzelm@18598
   565
the goal) as well as the theorems to use *)
wenzelm@18598
   566
fun subst_meth src =
wenzelm@18988
   567
  Method.syntax ((Scan.lift options_syntax) -- (Scan.lift ith_syntax) -- Attrib.thms) src
haftmann@21879
   568
  #> (fn (((asmflag, occL), inthms), ctxt) =>
wenzelm@18598
   569
    (if asmflag then eqsubst_asm_meth else eqsubst_meth) ctxt occL inthms);
paulson@15481
   570
wenzelm@18598
   571
wenzelm@16978
   572
val setup =
wenzelm@18833
   573
  Method.add_method ("subst", subst_meth, "single-step substitution");
paulson@15481
   574
wenzelm@16978
   575
end;