src/Tools/isac/ProgLang/evaluate.sml
author wneuper <Walther.Neuper@jku.at>
Sat, 04 Feb 2023 16:20:45 +0100
changeset 60673 ef24b1eed505
parent 60671 8998cb4818dd
child 60675 d841c720d288
permissions -rw-r--r--
eliminate use of Thy_Info 21: replace Unparse.term, TermC.unparse_ERROR for far off ctxt
     1 (* calculate values for function constants
     2    (c) Walther Neuper 000106
     3 
     4 Some formula transformations cannot be done by rewriting;
     5 these are done by structure Eval, which works tightly intertwined with structure Rewrite.
     6 *)
     7 
     8 signature EVALUATE =
     9 sig
    10   type ml
    11   type ml_fun
    12   val ml_fun_empty: ml_fun
    13   type ml_from_prog
    14 
    15   val is_num: term -> bool
    16   val calc_equ: string -> int * int -> bool
    17   val power: int -> int -> int
    18   val sign_mult: int -> int -> int
    19   val squfact: int -> int
    20   val gcd: int -> int -> int
    21   val sqrt: int -> int
    22   val cancel_int: int * int -> int * (int * int)
    23   val adhoc_thm: Proof.context -> Eval_Def.ml -> term -> (string * thm) option
    24   val adhoc_thm1_: Proof.context -> Eval_Def.ml -> term -> (string * thm) option
    25   val norm: term -> term
    26   val popt2str: Proof.context -> ('a * term) option -> string
    27   val int_of_numeral: term -> int
    28 \<^isac_test>\<open>
    29   val get_pair: Proof.context -> string -> Eval_Def.ml_fun -> term -> (string * term) option
    30   val mk_rule: term list * term * term -> term
    31   val divisors: int -> int list
    32   val doubles: int list -> int list
    33 \<close>
    34 end
    35 
    36 (**)
    37 structure Eval(**): EVALUATE(**) =
    38 struct
    39 (**)
    40 
    41 type ml = Eval_Def.ml
    42 type ml_fun = Eval_Def.ml_fun
    43 val ml_fun_empty =  Eval_Def.ml_fun_empty
    44 type ml_from_prog = Eval_Def.ml_from_prog
    45 
    46 val is_num = can HOLogic.dest_number;
    47 
    48 (* trace internal steps of isac's numeral calculations *)
    49 val eval_trace = Attrib.setup_config_bool \<^binding>\<open>eval_trace\<close> (K false);
    50 
    51 (** calculate integers **)
    52 
    53 fun calc_equ "less"  (n1, n2) = n1 < n2
    54   | calc_equ "less_eq" (n1, n2) = n1 <= n2
    55   | calc_equ op_ _ = raise ERROR ("calc_equ: operator = " ^ op_ ^ " not defined");
    56 fun sqrt (n:int) = if n < 0 then 0 else (trunc o Math.sqrt o Real.fromInt (*FIXME*)) n;
    57 fun power _ 0 = 1
    58   | power b n = 
    59     if n > 0 then b* (power b (n - 1))
    60     else raise ERROR ("power " ^ TermC.str_of_int b ^ " " ^ TermC.str_of_int n);
    61 fun gcd 0 b = b
    62   | gcd a b = if a < b then gcd (b mod a) a else gcd (a mod b) b;
    63 fun sign n =
    64   if n < 0 then ~1
    65 	else if n = 0 then 0 else 1;
    66 fun sign_mult n1 n2 = (sign n1) * (sign n2);
    67 
    68 fun cancel_int (i1, i2) =
    69   let
    70     val sg = sign_mult i1 i2;
    71     val gcd' = gcd (abs i1) (abs i2);
    72   in
    73     (sg, ((abs i1) div gcd', (abs i2) div gcd'))
    74   end;
    75 
    76 infix dvd;
    77 fun d dvd n = n mod d = 0;
    78 fun divisors n =
    79   let fun pdiv ds d n = 
    80     if d = n then d :: ds
    81     else if d dvd n then pdiv (d :: ds) d (n div d)
    82 	 else pdiv ds (d + 1) n
    83   in pdiv [] 2 n end;
    84 
    85 fun doubles ds = (* ds is ordered *)
    86   let fun dbls ds [] = ds
    87 	| dbls ds [ _ ] = ds
    88 	| dbls ds (i :: i' :: is) = if i = i' then dbls (i :: ds) is
    89 				else dbls ds (i'::is)
    90   in dbls [] ds end;
    91 fun squfact 0 = 0
    92   | squfact 1 = 1
    93   | squfact n = foldl op* (1, (doubles o divisors) n);
    94 
    95 
    96 (** calculate numerals **)
    97 
    98 fun popt2str ctxt (SOME (_, term)) = "SOME " ^ UnparseC.term_in_ctxt ctxt term (*TODO \<longrightarrow> str_of_termopt*)
    99   | popt2str _ NONE = "NONE";
   100 
   101 (* scan a term for applying eval_fn ef 
   102 args
   103   thy:
   104   op_: operator (as string) selecting the root of the pair
   105   ef : fn : (string -> term -> theory -> (string * term) option)
   106              ^^^^^^... for creating the string for the resulting theorem
   107   t  : term to be scanned
   108 result:
   109   (string * term) option: found by the eval_* -function of type
   110        fn : string -> string -> term -> theory -> (string * term) option
   111             ^^^^^^... the selecting operator op_ (variable for eval_binop)
   112 *)
   113 fun trace_calc0 ctxt str =
   114   if Config.get ctxt eval_trace then writeln ("### " ^ str) else ()
   115 fun trace_calc1 ctxt str1 str2 =
   116   if Config.get ctxt eval_trace then writeln (str1 ^ str2) else ()
   117 fun trace_calc2 ctxt str term popt =
   118   if Config.get ctxt eval_trace
   119   then writeln (str ^ UnparseC.term_in_ctxt ctxt term ^ " , " ^ popt2str ctxt popt) else ()
   120 fun trace_calc3 ctxt str term =
   121   if Config.get ctxt eval_trace then writeln ("### " ^ str ^ UnparseC.term_in_ctxt ctxt term) else ()
   122 fun trace_calc4 ctxt str t1 t2 =
   123   if Config.get ctxt eval_trace
   124   then writeln ("### " ^ str ^ UnparseC.term_in_ctxt ctxt t1 ^ " $ " ^ UnparseC.term_in_ctxt ctxt t2) else ()
   125 
   126 fun get_pair (*1*)ctxt  op_ (ef: ml_fun) (t as (Const (op0, _) $ arg)) =   (* unary fns *)
   127     if op_ = op0 then 
   128       let val popt = ef op_ t ctxt  
   129       in case popt of SOME _ => popt | NONE => get_pair ctxt  op_ ef arg end
   130     else get_pair ctxt  op_ ef arg
   131   | get_pair (*2*)ctxt "Prog_Expr.ident" ef (t as (Const ("Prog_Expr.ident", _) $ _ $ _ )) =
   132     ef "Prog_Expr.ident" t ctxt                                                   (* not nested *)
   133   | get_pair (*3*)ctxt op_ ef (t as (Const (op0, _) $ t1 $ t2)) =                (* binary funs *)
   134     (trace_calc1 ctxt "1.. get_pair: binop = " op_;
   135     if op_ = op0 then 
   136       let
   137         val popt = ef op_ t ctxt
   138         val _ = trace_calc2 ctxt "2.. get_pair: " t popt
   139       in case popt of SOME _ => popt | NONE => 
   140         let
   141           val popt = get_pair ctxt op_ ef t1
   142           val _ = trace_calc2 ctxt "3.. get_pair: " t1  popt
   143         in case popt of SOME _ => popt | NONE => get_pair ctxt op_ ef t2 end (* search subterms *)
   144       end
   145     else                                                                    (* search subterms *)
   146       let
   147         val popt = get_pair ctxt op_ ef t1
   148         val _ = trace_calc2 ctxt "4.. get_pair: " t popt
   149       in case popt of SOME _ => popt | NONE => get_pair ctxt op_ ef t2 end)
   150   | get_pair (*4*)ctxt op_ ef (t as (Const (op0, _) $ t1 $ t2 $ t3)) =          (* ternary funs *)
   151     (trace_calc3 ctxt "get_pair 4a: t= "t;
   152     trace_calc1 ctxt "get_pair 4a: op_= " op_;
   153     trace_calc1 ctxt "get_pair 4a: op0= " op0; 
   154     if op_ = op0 then 
   155       case ef op_ t ctxt of st as SOME _ => st | NONE => 
   156         (case get_pair ctxt op_ ef t2 of st as SOME _ => st | NONE => get_pair ctxt op_ ef t3)
   157     else 
   158       (case get_pair ctxt op_ ef t1 of st as SOME _ => st | NONE => 
   159         (case get_pair ctxt op_ ef t2 of st as SOME _ => st | NONE => get_pair ctxt op_ ef t3)))
   160   | get_pair (*5*)ctxt op_ ef (Abs (_, _, body)) = get_pair ctxt op_ ef body
   161   | get_pair (*6*)ctxt op_ ef (t1 $ t2) = 
   162     let
   163       val _ = trace_calc4 ctxt "5.. get_pair t1 $ t2: " t1 t2;
   164       val popt = get_pair ctxt op_ ef t1
   165     in case popt of SOME _ => popt 
   166       | NONE => (trace_calc0 ctxt "### get_pair: t1 $ t2 -> NONE"; get_pair ctxt op_ ef t2) 
   167     end
   168   | get_pair (*7*)_ _ _ _ = NONE
   169 
   170 (* get a thm from an op_ somewhere in a term by use of get_pair *)
   171 fun adhoc_thm ctxt (op_, eval_fn) t =
   172 ((*@{print\<open>tracing\<close>}{a = "adhoc_thm", op_ = op_, t = t, get_p = get_pair thy op_ eval_fn t};*)
   173   case get_pair ctxt op_ eval_fn t of
   174     NONE => NONE
   175   | SOME (thmid, t') => SOME (thmid, Skip_Proof.make_thm (Proof_Context.theory_of ctxt) t'));
   176 
   177 (* get a thm applying an op_ to a term by direct use of eval_fn *)
   178 fun adhoc_thm1_ ctxt (op_, eval_fn) ct =
   179   case eval_fn op_ ct ctxt of
   180     NONE => NONE
   181   | SOME (thmid, t') => SOME (thmid, Skip_Proof.make_thm (Proof_Context.theory_of ctxt) t');
   182 
   183 (** for ordered and conditional rewriting **)
   184 
   185 fun mk_rule (prems, l, r) = 
   186     HOLogic.Trueprop $ (Logic.list_implies (prems, TermC.mk_equality (l, r)));
   187 
   188 (* 'norms' a rule, e.g.
   189 (*1*) from a = 1 ==> a*(b+c) = b+c 
   190       to   a = 1 ==> a*(b+c) = b+c                     no change
   191 (*2*) from t = t
   192       to  (t = t) = True                               !!
   193 (*3*) from [| k < l; m + l = k + n |] ==> m < n
   194       to   [| k < l; m + l = k + n |] ==> m < n = True !! *)
   195 fun norm rule =
   196   let
   197     val (prems, concl) = 
   198       (map TermC.strip_trueprop (Logic.strip_imp_prems rule),
   199         (TermC.strip_trueprop o  Logic.strip_imp_concl) rule)
   200   in
   201     if TermC.is_equality concl
   202     then 
   203       let val (l, r) = TermC.dest_equals concl
   204       in
   205         if l = r then (*2*) mk_rule (prems, concl, @{term True}) else (*1*) rule 
   206       end
   207     else (*3*) mk_rule (prems, concl, @{term True})
   208   end;
   209 
   210 (* preliminary HACK *)
   211 fun int_of_numeral (Const (\<^const_name>\<open>zero_class.zero\<close>, _)) = 0
   212   | int_of_numeral (Const (\<^const_name>\<open>one_class.one\<close>, _)) = 1
   213   | int_of_numeral (Const (\<^const_name>\<open>uminus\<close>, _) $ t) = ~1 * int_of_numeral t
   214   | int_of_numeral (Const (\<^const_name>\<open>numeral\<close>, _) $ n) = HOLogic.dest_numeral n
   215   | int_of_numeral t = raise TERM ("int_of_numeral", [t]);
   216 
   217 end
   218 
   219 
   220 
   221 
   222