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