src/Tools/isac/ProgLang/Auto_Prog.thy
author wneuper <Walther.Neuper@jku.at>
Tue, 10 Jan 2023 17:07:53 +0100
changeset 60647 ea7db4f4f837
parent 60588 9a116f94c5a6
child 60664 ed6f9e67349d
permissions -rw-r--r--
eliminate use of Thy_Info 10: arg. ctxt for Rule.to_string finished
     1 (* Title:  ProgLang/Auto_Prog
     2    Author: Walther Neuper, Aug.2019
     3    (c) due to copyright terms
     4 *)
     5 
     6 theory Auto_Prog imports Prog_Tac Tactical begin
     7 
     8 text \<open>Abstract:
     9   The tactics Rewrite_Set* create ONE step in a calculation by application of usually
    10   MORE than one theorem (here called "rule").
    11   However, students can request details of rewriting down to single applications of theorems.
    12   For accomplishing such requests, a program is auto-generated from the items of a rule-set.
    13 \<close>
    14 
    15 subsection \<open>consts for programs automatically built from rules\<close>
    16 
    17 partial_function (tailrec) auto_generated :: "'z \<Rightarrow> 'z"
    18   where "auto_generated t_t = t_t"
    19 partial_function (tailrec) auto_generated_inst :: "'z \<Rightarrow> real \<Rightarrow> 'z"
    20   where "auto_generated_inst t_t v =  t_t"
    21 
    22 
    23 subsection \<open>TODO: code for above\<close>
    24 ML \<open>
    25 \<close> ML \<open>
    26 signature AUTO_GERNERATE_PROGRAM =
    27   sig
    28     val contain_bdv: Rule.rule list -> bool
    29     val contains_bdv: thm -> bool
    30     val subst_typs: term -> typ -> typ -> term
    31     val pblterm: ThyC.id -> Probl_Def.id -> term
    32     val subpbl: string -> string list -> term
    33     val stacpbls: term -> term list
    34     val op_of_calc: term -> string
    35     val get_calcs: theory -> term -> Eval_Def.ml_from_prog list
    36     val prep_rls: theory -> Rule_Set.T -> Rule_Set.T (*ren insert*)
    37     val gen: theory -> term -> Rule_Set.T -> term
    38 \<^isac_test>\<open>
    39     val subst_typ: string -> typ -> term list -> (typ * typ) list
    40     val is_calc: term -> bool
    41     val rule2stac: theory -> Rule.rule -> term
    42     val rule2stac_inst: theory -> Rule.rule -> term
    43     val #> : term list -> term
    44     val rules2scr_Rls : theory -> Rule.rule list -> term
    45     val rules2scr_Seq : theory -> Rule.rule list -> term
    46 \<close>
    47   end
    48 (**)
    49 structure Auto_Prog(**): AUTO_GERNERATE_PROGRAM(**) =
    50 struct
    51 (**)
    52 
    53 (** build up a program from rules **)
    54 
    55 (* make the term 'Subproblem (domID, pblID)' to a formula for frontend;
    56   needs to be here after def. Subproblem in Prog_Tac.thy *)
    57 val subpbl_t $ (pair_t $ _ $ _) = (TermC.parseNEW'' @{theory Prog_Tac})
    58   "Subproblem (''Isac_Knowledge'',[''equation'',''univar''])"
    59 
    60 fun subpbl domID pblID =
    61   subpbl_t $ (pair_t $ HOLogic.mk_string domID $ 
    62     list_comb (Syntax.const @{const_syntax Char}, map HOLogic.mk_string pblID));
    63 fun pblterm domID pblID =
    64   pair_t $ HOLogic.mk_string domID $ 
    65     list_comb (Syntax.const @{const_syntax Char}, map HOLogic.mk_string pblID);
    66 
    67 (* fetch tactics from a program omitting tacticals like While, Repeat,.. *)
    68 fun stacpbls (_ $ body) =
    69     let
    70       fun scan (Const (\<^const_name>\<open>Let\<close>, _) $ e $ (Abs (_, _, b))) = (scan e) @ (scan b)
    71         | scan (Const (\<^const_name>\<open>Tactical.If\<close>, _) $ _ $ e1 $ e2) = (scan e1) @ (scan e2)
    72         | scan (Const (\<^const_name>\<open>Tactical.While\<close>, _) $ _ $ e $ _) = scan e
    73         | scan (Const (\<^const_name>\<open>Tactical.While\<close>, _) $ _ $ e) = scan e
    74         | scan (Const (\<^const_name>\<open>Tactical.Repeat\<close>, _) $ e $ _) = scan e
    75         | scan (Const (\<^const_name>\<open>Tactical.Repeat\<close>, _) $ e) = scan e
    76         | scan (Const (\<^const_name>\<open>Tactical.Try\<close>, _) $ e $ _) = scan e
    77         | scan (Const (\<^const_name>\<open>Tactical.Try\<close>, _) $ e) = scan e
    78         | scan (Const (\<^const_name>\<open>Tactical.Or\<close>, _) $ e1 $ e2 $ _) = (scan e1) @ (scan e2)
    79         | scan (Const (\<^const_name>\<open>Tactical.Or\<close>, _) $ e1 $ e2) = (scan e1) @ (scan e2)
    80         | scan (Const (\<^const_name>\<open>Tactical.Chain\<close>, _) $ e1 $ e2 $ _) = (scan e1) @ (scan e2)
    81         | scan (Const (\<^const_name>\<open>Tactical.Chain\<close>, _) $ e1 $ e2) = (scan e1) @ (scan e2)
    82         | scan t = case Prog_Tac.eval_leaf [] NONE TermC.empty t of
    83   			  (Program.Tac _, _) => [t] | (Program.Expr _, _) => []
    84     in ((distinct op =) o scan) body end
    85   | stacpbls t = raise ERROR ("fun stacpbls not applicable to '" ^ UnparseC.term t ^ "'")
    86 
    87 (* get operators out of a program *)
    88 fun is_calc (Const (\<^const_name>\<open>Prog_Tac.Calculate\<close>,_) $ _) = true
    89   | is_calc (Const (\<^const_name>\<open>Prog_Tac.Calculate\<close>,_) $ _ $ _) = true
    90   | is_calc _ = false;
    91 fun op_of_calc (Const (\<^const_name>\<open>Prog_Tac.Calculate\<close>,_) $ op_) = HOLogic.dest_string op_
    92   | op_of_calc (Const (\<^const_name>\<open>Prog_Tac.Calculate\<close>,_) $ op_ $ _) = HOLogic.dest_string op_
    93   | op_of_calc t = raise ERROR ("op_of_calc called with " ^ UnparseC.term t);
    94 fun get_calcs thy sc =
    95     sc
    96     |> stacpbls
    97     |> filter is_calc
    98     |> map op_of_calc
    99     |> (get_calc (Proof_Context.init_global thy) |> map);
   100 
   101 (** build up a program from rules **)
   102 
   103 (* transform type rule to a term *)
   104 (*WN060605 script-arg (t_::'z) and "Free (t_, 'a)" at end of body are inconsistent !!!*)
   105 val (FunID_Term $ _) = Program.prep_program @{thm auto_generated.simps}
   106 val (FunID_Term_Bdv $ _) = Program.prep_program @{thm auto_generated_inst.simps}
   107 val Repeat $ _ = (TermC.inst_abs o (TermC.parseNEW'' @{theory}))
   108 	"Repeat (Rewrite ''real_diff_minus'' t)";
   109 val Try $ _ = (TermC.inst_abs o (TermC.parseNEW'' @{theory}))
   110 	"Try (Rewrite ''real_diff_minus'' t)";
   111 val Cal $ _ = (TermC.inst_abs o (TermC.parseNEW'' @{theory}))
   112 	"Calculate ''PLUS''";
   113 val Ca1 $ _ = (TermC.inst_abs o (TermC.parseNEW'' @{theory}))
   114 	"Calculate1 ''PLUS''";
   115 val Rew $ _ $ _ = (TermC.inst_abs o (TermC.parseNEW'' @{theory}))
   116 	"Rewrite ''real_diff_minus'' t";
   117 (*this is specific to FunHead_inst ...*)
   118 val Rew_Inst $ Subs $ _ = (TermC.inst_abs o (TermC.parseNEW'' @{theory}))
   119 	"Rewrite_Inst [(''bdv'',v)] ''real_diff_minus''";
   120 val Rew_Set $ _ = (TermC.inst_abs o (TermC.parseNEW'' @{theory}))
   121 	"Rewrite_Set ''real_diff_minus''";
   122 val Rew_Set_Inst $ _ $ _ = (TermC.inst_abs o (TermC.parseNEW'' @{theory}))
   123 	"Rewrite_Set_Inst [(''bdv'',v)] ''real_diff_minus''";
   124 val SEq $ _ $ _ $ _ = (TermC.inst_abs o (TermC.parseNEW'' @{theory}))
   125 	"  ((Try (Repeat (Rewrite ''real_diff_minus''))) #>  \
   126         \   (Try (Repeat (Rewrite ''add.commute''))) #> \
   127         \   (Try (Repeat (Rewrite ''mult_commute'')))) t"; (*has not yet been needed*)
   128 
   129 fun rule2stac _ (Rule.Thm (thmID, _)) = Try $ (Repeat $ (Rew $ HOLogic.mk_string thmID))
   130   | rule2stac thy (Rule.Eval (c, _)) = Try $ (Repeat $ (Cal $ HOLogic.mk_string 
   131     (get_calc_prog_id (Proof_Context.init_global thy) c)))
   132   | rule2stac thy (Rule.Cal1 (c, _)) = Try $ (Repeat $ (Ca1 $ HOLogic.mk_string 
   133     (get_calc_prog_id (Proof_Context.init_global thy) c)))
   134   | rule2stac _ (Rule.Rls_ rls) = Try $ (Rew_Set $ HOLogic.mk_string (Rule_Set.id rls))
   135   | rule2stac thy r = raise ERROR ("rule2stac: not applicable to \"" ^
   136       Rule.to_string (Proof_Context.init_global thy) r ^ "\"");
   137 fun rule2stac_inst _ (Rule.Thm (thmID, _)) = 
   138     Try $ (Repeat $ (Rew_Inst $ Subs $ HOLogic.mk_string thmID))
   139   | rule2stac_inst thy (Rule.Eval (c, _)) = 
   140     Try $ (Repeat $ (Cal $ HOLogic.mk_string (get_calc_prog_id (Proof_Context.init_global thy) c)))
   141   | rule2stac_inst thy (Rule.Cal1 (c, _)) = 
   142     Try $ (Repeat $ (Cal $ HOLogic.mk_string (get_calc_prog_id (Proof_Context.init_global thy) c)))
   143   | rule2stac_inst _ (Rule.Rls_ rls) = 
   144     Try $ (Rew_Set_Inst $ Subs $ HOLogic.mk_string (Rule_Set.id rls))
   145   | rule2stac_inst thy r = raise ERROR ("rule2stac_inst: not applicable to \"" ^
   146       Rule.to_string (Proof_Context.init_global thy) r ^ "\"");
   147 
   148 (*for appropriate nesting take stacs in _reverse_ order*)
   149 fun op #>@ sts [s] = SEq $ s $ sts
   150   | op #>@ sts (s::ss) = op #>@ (SEq $ s $ sts) ss
   151   | op #>@ t ts =
   152     raise ERROR ("fun #>@ not applicable to \"" ^ UnparseC.term t ^ "\" \"" ^ UnparseC.terms ts  ^ "\"");
   153 (*IS NOT*)
   154 fun op #> [stac] = stac
   155   | op #> [s1, s2] = SEq $ s1 $ s2
   156   | op #> stacs = case rev stacs of
   157       s3 :: s2 :: ss => op #>@ (SEq $ s2 $ s3) ss
   158     | ts => raise ERROR ("fun #> not applicable to \"" ^ UnparseC.terms ts ^ "\"")
   159 
   160 val contains_bdv = not o null o filter TermC.is_bdv o TermC.ids2str o Thm.prop_of;
   161 
   162 (* does a rule contain a 'bdv'; descend recursively into Rls_ *)
   163 fun contain_bdv [] = false
   164   | contain_bdv (Rule.Thm (_, thm) :: rs) = 
   165     if (not o contains_bdv) thm
   166     then contain_bdv rs
   167     else true
   168   | contain_bdv (Rule.Eval _ :: rs) = contain_bdv rs
   169   | contain_bdv (Rule.Cal1 _ :: rs) = contain_bdv rs
   170   | contain_bdv (Rule.Rls_ rls :: rs) = 
   171     contain_bdv (Rule_Set.get_rules rls) orelse contain_bdv rs
   172   | contain_bdv (r :: _) = 
   173     raise ERROR ("contain_bdv called with [" ^ Rule.id r ^ ",...]");
   174 
   175 (* filter Frees for free_str and pair their respective types with typ *)
   176 fun subst_typ free_str typ frees =
   177   let
   178     val vars_v = filter (fn t => curry op = (t |> dest_Free |> fst) free_str) frees
   179     val typs_v = map (fn t => (t |> dest_Free |> snd)) vars_v
   180   in
   181     map (fn T => (T, typ)) typs_v
   182   end
   183 (* instantiate typs in Prog auto_generated or auto_generated_ins for args "t_t", "v" *)
   184 fun subst_typs prog typ_t typ_bdv =
   185   let
   186     val args = Program.formal_args prog
   187     val frees = TermC.vars prog
   188     val prog' = subst_atomic_types (subst_typ "t_t" typ_t frees) prog
   189   in
   190     if length args <= 1
   191     then
   192       prog'
   193     else (* auto_generated_inst has second argument "v" *)
   194       subst_atomic_types (subst_typ "v" typ_bdv frees) prog'
   195   end
   196 
   197 fun rules2scr_Rls thy rules =
   198     if contain_bdv rules
   199     then FunID_Term_Bdv $ (Repeat $ (((op #> o (map (rule2stac_inst thy))) rules) $ TermC.empty))
   200     else FunID_Term $ (Repeat $ (((op #> o (map (rule2stac thy))) rules) $ TermC.empty));
   201 fun rules2scr_Seq thy rules =
   202     if contain_bdv rules
   203     then FunID_Term_Bdv $ (((op #> o (map (rule2stac_inst thy))) rules) $ TermC.empty)
   204     else FunID_Term $ (((op #> o (map (rule2stac thy))) rules) $ TermC.empty);
   205 
   206 (* REPLACED BY Auto_Prog.gen:
   207    prepare the input for an rls for use:
   208    # generate a program for stepwise execution of the rls
   209    # filter the operators for Eval out of the script ?WN111014?
   210    use this function while storing (TODO integrate..) into Know_Store.add_rlss
   211 *)
   212 fun prep_rls _ Rule_Set.Empty = raise ERROR "prep_rls: not required for Erls"
   213   | prep_rls thy (Rule_Def.Repeat {id, preconds, rew_ord, asm_rls, prog_rls, rules, errpatts, ...}) = 
   214       let
   215         val sc = rules2scr_Rls thy rules
   216       in
   217         Rule_Def.Repeat {id = id, preconds = preconds, rew_ord = rew_ord, asm_rls = asm_rls, prog_rls = prog_rls,
   218   	      calc = get_calcs thy sc,
   219   	      rules = rules, errpatts = errpatts,
   220   	      program = Rule.Empty_Prog (*Rule.Prog sc  AD-HOC REPLACED BY Auto_Prog.gen*)} end
   221   | prep_rls thy (Rule_Set.Sequence {id, preconds, rew_ord, asm_rls, prog_rls, rules, errpatts, ...}) = 
   222       let
   223         val sc = (rules2scr_Seq thy rules)
   224       in
   225         Rule_Set.Sequence {id = id, preconds = preconds, rew_ord = rew_ord, asm_rls = asm_rls, prog_rls = prog_rls,
   226 	        calc = get_calcs thy sc,
   227 	        rules = rules, errpatts = errpatts,
   228   	      program = Rule.Empty_Prog (*Rule.Prog sc  AD-HOC REPLACED BY Auto_Prog.gen*)} end
   229   | prep_rls _ (Rule_Set.Rrls {id, ...}) = 
   230       raise ERROR ("prep_rls: not required for Rrls \"" ^ id ^ "\"");
   231 
   232 (* on the fly generate a Prog from an rls for Detail_Step.go.
   233   Types are not precise, but these are not required by LI.
   234   Argument "thy" is only required for lookup in Know_Store.
   235 *)
   236 fun gen thy t rls =
   237   let
   238     val prog = case rls of
   239 	      Rule_Def.Repeat {rules, ...} => rules2scr_Rls thy rules
   240 	    | Rule_Set.Sequence {rules, ...} => rules2scr_Seq thy rules
   241 	    | _ => raise ERROR ("Auto_Prog.gen: not for rule-set \"" ^ Rule_Set.id rls ^ "\"")
   242   in
   243     subst_typs prog (type_of t) (TermC.guess_bdv_typ t)
   244   end
   245 
   246 (**)end(*Auto_Prog*)
   247 \<close> ML \<open>
   248 \<close> ML \<open>
   249 \<close> 
   250 end