src/Tools/isac/ProgLang/calculate.sml
author Walther Neuper <walther.neuper@jku.at>
Sat, 04 Apr 2020 12:11:32 +0200
changeset 59850 f3cac3053e7b
parent 59785 b5de2ec15f36
child 59853 e18f30c44998
permissions -rw-r--r--
separate Rule_Set from Rule
neuper@37906
     1
(* calculate values for function constants
neuper@37906
     2
   (c) Walther Neuper 000106
neuper@37906
     3
*)
neuper@37906
     4
wneuper@59387
     5
signature NUMERAL_CALCULATION =
wneuper@59386
     6
  sig
walther@59619
     7
    type float
wneuper@59401
     8
    val calc_equ: string -> int * int -> bool
wneuper@59401
     9
    val power: int -> int -> int
wneuper@59401
    10
    val sign_mult: int -> int -> int
wneuper@59401
    11
    val squfact: int -> int
wneuper@59401
    12
    val gcd: int -> int -> int
wneuper@59401
    13
    val sqrt: int -> int
wneuper@59416
    14
    val adhoc_thm: theory -> string * Rule.eval_fn -> term -> (string * thm) option
walther@59850
    15
    val adhoc_thm1_: theory -> Rule_Set.cal -> term -> (string * thm) option
wneuper@59386
    16
    val norm: term -> term
wneuper@59386
    17
    val popt2str: ('a * term) option -> string
walther@59619
    18
    val numeral: term -> ((int * int) * (int * int)) option
walther@59619
    19
    val calcul: string -> float -> float -> float
walther@59619
    20
    val term_of_float: typ -> float -> term
walther@59619
    21
    val var_op_float: term -> string -> typ -> typ ->float -> term
walther@59619
    22
    val float_op_var: term -> string -> typ -> typ -> float -> term
wneuper@59386
    23
(* ---- for tests only: shifted from below to remove the Warning "unused" at fun.def. --------- *)
wneuper@59386
    24
  (* NONE *)
walther@59785
    25
(*/-------------------------------------------------------- ! aktivate for Test_Isac BEGIN ---\* )
wneuper@59416
    26
    val get_pair: theory -> string -> Rule.eval_fn -> term -> (string * term) option
wneuper@59386
    27
    val mk_rule: term list * term * term -> term
wneuper@59403
    28
    val divisors: int -> int list
wneuper@59403
    29
    val doubles: int list -> int list
walther@59785
    30
( *\--- ! aktivate for Test_Isac END ----------------------------------------------------------/*)
wneuper@59386
    31
  end
wneuper@59386
    32
wneuper@59386
    33
(**)
walther@59773
    34
structure Num_Calc(**): NUMERAL_CALCULATION(**) =
wneuper@59386
    35
struct
wneuper@59386
    36
(**)
neuper@37906
    37
walther@59619
    38
type float =
walther@59619
    39
  (int * int)   (* value:     significand * exponent *)
walther@59619
    40
  * (int * int) (* precision: significand * exponent *)
walther@59619
    41
wneuper@59401
    42
(** calculate integers **)
wneuper@59401
    43
wneuper@59401
    44
fun calc_equ "less"  (n1, n2) = n1 < n2
wneuper@59401
    45
  | calc_equ "less_eq" (n1, n2) = n1 <= n2
wneuper@59401
    46
  | calc_equ op_ _ = error ("calc_equ: operator = " ^ op_ ^ " not defined");
wneuper@59401
    47
fun sqrt (n:int) = if n < 0 then 0 else (trunc o Math.sqrt o Real.fromInt (*FIXME*)) n;
wneuper@59401
    48
fun power _ 0 = 1
wneuper@59401
    49
  | power b n = 
wneuper@59401
    50
    if n > 0 then b* (power b (n - 1))
wneuper@59401
    51
    else error ("power " ^ TermC.str_of_int b ^ " " ^ TermC.str_of_int n);
wneuper@59401
    52
fun gcd 0 b = b
wneuper@59401
    53
  | gcd a b = if a < b then gcd (b mod a) a else gcd (a mod b) b;
wneuper@59401
    54
fun sign n =
wneuper@59401
    55
  if n < 0 then ~1
wneuper@59401
    56
	else if n = 0 then 0 else 1;
wneuper@59401
    57
fun sign_mult n1 n2 = (sign n1) * (sign n2);
wneuper@59401
    58
wneuper@59401
    59
infix dvd;
wneuper@59401
    60
fun d dvd n = n mod d = 0;
wneuper@59401
    61
fun divisors n =
wneuper@59401
    62
  let fun pdiv ds d n = 
wneuper@59401
    63
    if d = n then d :: ds
wneuper@59401
    64
    else if d dvd n then pdiv (d :: ds) d (n div d)
wneuper@59401
    65
	 else pdiv ds (d + 1) n
wneuper@59401
    66
  in pdiv [] 2 n end;
wneuper@59401
    67
wneuper@59401
    68
fun doubles ds = (* ds is ordered *)
wneuper@59401
    69
  let fun dbls ds [] = ds
wneuper@59401
    70
	| dbls ds [ _ ] = ds
wneuper@59401
    71
	| dbls ds (i :: i' :: is) = if i = i' then dbls (i :: ds) is
wneuper@59401
    72
				else dbls ds (i'::is)
wneuper@59401
    73
  in dbls [] ds end;
wneuper@59401
    74
fun squfact 0 = 0
wneuper@59401
    75
  | squfact 1 = 1
wneuper@59401
    76
  | squfact n = foldl op* (1, (doubles o divisors) n);
wneuper@59401
    77
wneuper@59401
    78
neuper@37906
    79
(** calculate numerals **)
neuper@37906
    80
wneuper@59416
    81
fun popt2str (SOME (_, term)) = "SOME " ^ Rule.term2str term (*TODO \<longrightarrow> str_of_termopt*)
neuper@37906
    82
  | popt2str NONE = "NONE";
neuper@37906
    83
neuper@37906
    84
(* scan a term for applying eval_fn ef 
neuper@37906
    85
args
neuper@37906
    86
  thy:
neuper@37906
    87
  op_: operator (as string) selecting the root of the pair
neuper@37906
    88
  ef : fn : (string -> term -> theory -> (string * term) option)
neuper@37906
    89
             ^^^^^^... for creating the string for the resulting theorem
neuper@37906
    90
  t  : term to be scanned
neuper@37906
    91
result:
neuper@37906
    92
  (string * term) option: found by the eval_* -function of type
neuper@37906
    93
       fn : string -> string -> term -> theory -> (string * term) option
neuper@37906
    94
            ^^^^^^... the selecting operator op_ (variable for eval_binop)
neuper@37906
    95
*)
wneuper@59387
    96
fun trace_calc0 str =
wneuper@59405
    97
  if ! Celem.trace_calc then writeln ("### " ^ str) else ()
wneuper@59387
    98
fun trace_calc1 str1 str2 =
wneuper@59405
    99
  if ! Celem.trace_calc then writeln (str1 ^ str2) else ()
wneuper@59387
   100
fun trace_calc2 str term popt =
wneuper@59416
   101
  if ! Celem.trace_calc then writeln (str ^ Rule.term2str term ^ " , " ^ popt2str popt) else ()
wneuper@59387
   102
fun trace_calc3 str term =
wneuper@59416
   103
  if ! Celem.trace_calc then writeln ("### " ^ str ^ Rule.term2str term) else ()
wneuper@59387
   104
fun trace_calc4 str t1 t2 =
wneuper@59416
   105
  if ! Celem.trace_calc then writeln ("### " ^ str ^ Rule.term2str t1 ^ " $ " ^ Rule.term2str t2) else ()
wneuper@59387
   106
wneuper@59416
   107
fun get_pair thy op_ (ef: Rule.eval_fn) (t as (Const (op0, _) $ arg)) =                (* unary fns *)
neuper@37906
   108
    if op_ = op0 then 
neuper@55487
   109
      let val popt = ef op_ t thy 
neuper@55487
   110
      in case popt of SOME _ => popt | NONE => get_pair thy op_ ef arg end
neuper@37906
   111
    else get_pair thy op_ ef arg
walther@59603
   112
  | get_pair thy "Prog_Expr.ident" ef (t as (Const ("Prog_Expr.ident", _) $ _ $ _ )) =
walther@59603
   113
    ef "Prog_Expr.ident" t thy                                                      (* not nested *)
neuper@55487
   114
  | get_pair thy op_ ef (t as (Const (op0,_) $ t1 $ t2)) =                      (* binary funs *)
wneuper@59387
   115
    (trace_calc1 "1.. get_pair: binop = " op_;
neuper@55487
   116
    if op_ = op0 then 
wneuper@59387
   117
      let
wneuper@59387
   118
        val popt = ef op_ t thy
wneuper@59387
   119
        val _ = trace_calc2 "2.. get_pair: " t popt
neuper@55487
   120
      in case popt of SOME _ => popt | NONE => 
wneuper@59387
   121
        let
wneuper@59387
   122
          val popt = get_pair thy op_ ef t1
wneuper@59387
   123
          val _ = trace_calc2 "3.. get_pair: " t1  popt
neuper@55487
   124
        in case popt of SOME _ => popt | NONE => get_pair thy op_ ef t2 end
neuper@55487
   125
      end
neuper@55487
   126
    else                                                                    (* search subterms *)
wneuper@59387
   127
      let
wneuper@59387
   128
        val popt = get_pair thy op_ ef t1
wneuper@59387
   129
        val _ = trace_calc2 "4.. get_pair: " t popt
neuper@55487
   130
      in case popt of SOME _ => popt | NONE => get_pair thy op_ ef t2 end)
neuper@55487
   131
  | get_pair thy op_ ef (t as (Const (op0, _) $ t1 $ t2 $ t3)) =               (* ternary funs *)
wneuper@59387
   132
    (trace_calc3 "get_pair 4a: t= "t;
wneuper@59387
   133
    trace_calc1 "get_pair 4a: op_= " op_;
wneuper@59387
   134
    trace_calc1 "get_pair 4a: op0= " op0; 
neuper@55487
   135
    if op_ = op0 then 
neuper@55487
   136
      case ef op_ t thy of st as SOME _ => st | NONE => 
neuper@55487
   137
        (case get_pair thy op_ ef t2 of st as SOME _ => st | NONE => get_pair thy op_ ef t3)
neuper@55487
   138
    else 
neuper@55487
   139
      (case get_pair thy op_ ef t1 of st as SOME _ => st | NONE => 
neuper@55487
   140
        (case get_pair thy op_ ef t2 of st as SOME _ => st | NONE => get_pair thy op_ ef t3)))
neuper@55487
   141
  | get_pair thy op_ ef (Abs (_, _, body)) = get_pair thy op_ ef body
neuper@55487
   142
  | get_pair thy op_ ef (t1 $ t2) = 
wneuper@59387
   143
    let
wneuper@59387
   144
      val _ = trace_calc4 "5.. get_pair t1 $ t2: " t1 t2;
neuper@55487
   145
      val popt = get_pair thy op_ ef t1
neuper@55487
   146
    in case popt of SOME _ => popt 
wneuper@59387
   147
      | NONE => (trace_calc0 "### get_pair: t1 $ t2 -> NONE"; get_pair thy op_ ef t2) 
neuper@55487
   148
    end
neuper@55487
   149
  | get_pair _ _ _ _ = NONE
neuper@37906
   150
wneuper@59387
   151
(* get a thm from an op_ somewhere in the term;
wneuper@59387
   152
   apply ONLY to (uminus_to_string term), uminus_to_string (- 4711) --> (-4711) *)
wneuper@59255
   153
fun adhoc_thm thy (op_, eval_fn) ct =
neuper@37906
   154
  case get_pair thy op_ eval_fn ct of
wneuper@59387
   155
    NONE =>  NONE
wneuper@59185
   156
  | SOME (thmid, t) => SOME (thmid, (Thm.make_thm o (Thm.global_cterm_of thy)) t);
neuper@37906
   157
wneuper@59387
   158
(* get a thm applying an op_ to a term;
wneuper@59387
   159
   apply ONLY to (numbers_to_string term), numbers_to_string (- 4711) --> (-4711) *)
wneuper@59387
   160
fun adhoc_thm1_ thy (op_, eval_fn) ct =
neuper@37906
   161
    case eval_fn op_ ct thy of
neuper@37906
   162
	NONE => NONE
neuper@37906
   163
      | SOME (thmid,t) =>
wneuper@59185
   164
	SOME (thmid, (Thm.make_thm o (Thm.global_cterm_of thy)) t);
neuper@37906
   165
wneuper@59387
   166
(** for ordered and conditional rewriting **)
neuper@37906
   167
wneuper@59389
   168
fun mk_rule (prems, l, r) = 
wneuper@59390
   169
    HOLogic.Trueprop $ (Logic.list_implies (prems, TermC.mk_equality (l, r)));
neuper@37906
   170
neuper@37906
   171
(* 'norms' a rule, e.g.
neuper@41924
   172
(*1*) from a = 1 ==> a*(b+c) = b+c 
neuper@41924
   173
      to   a = 1 ==> a*(b+c) = b+c                     no change
neuper@41924
   174
(*2*) from t = t
neuper@41924
   175
      to  (t = t) = True                               !!
neuper@41924
   176
(*3*) from [| k < l; m + l = k + n |] ==> m < n
neuper@41924
   177
      to   [| k < l; m + l = k + n |] ==> m < n = True !! *)
neuper@37906
   178
fun norm rule =
neuper@37906
   179
  let
wneuper@59391
   180
    val (prems, concl) = 
wneuper@59391
   181
      (map TermC.strip_trueprop (Logic.strip_imp_prems rule),
wneuper@59391
   182
        (TermC.strip_trueprop o  Logic.strip_imp_concl) rule)
wneuper@59391
   183
  in
wneuper@59391
   184
    if TermC.is_equality concl
wneuper@59391
   185
    then 
wneuper@59391
   186
      let val (l, r) = TermC.dest_equals concl
wneuper@59391
   187
      in
wneuper@59391
   188
        if l = r then (*2*) mk_rule (prems, concl, @{term True}) else (*1*) rule 
wneuper@59391
   189
      end
wneuper@59391
   190
    else (*3*) mk_rule (prems, concl, @{term True})
neuper@37906
   191
  end;
neuper@37906
   192
walther@59619
   193
(* convert int and float to internal floatingpoint prepresentation.*)
walther@59619
   194
fun numeral (Free (str, _)) = 
walther@59619
   195
    (case TermC.int_of_str_opt str of
walther@59619
   196
	 SOME i => SOME ((i, 0), (0, 0))
walther@59619
   197
       | NONE => NONE)
walther@59619
   198
  | numeral (Const ("Float.Float", _) $
walther@59619
   199
		   (Const ("Product_Type.Pair", _) $
walther@59619
   200
			  (Const ("Product_Type.Pair", _) $ Free (v1, _) $ Free (v2,_)) $
walther@59619
   201
			  (Const ("Product_Type.Pair", _) $ Free (p1, _) $ Free (p2,_))))=
walther@59619
   202
    (case (TermC.int_of_str_opt v1, TermC.int_of_str_opt v2, TermC.int_of_str_opt p1, TermC.int_of_str_opt p2) of
walther@59619
   203
	(SOME v1', SOME v2', SOME p1', SOME p2') =>
walther@59619
   204
	SOME ((v1', v2'), (p1', p2'))
walther@59619
   205
      | _ => NONE)
walther@59619
   206
  | numeral _ = NONE;
walther@59619
   207
walther@59619
   208
(*** handle numerals in eval_binop ***)
walther@59619
   209
(* TODO rebuild fun calcul, fun term_of_float,fun var_op_float, fun float_op_var:
walther@59619
   210
   Float ((a, b), _:int * int, (c, d), _:int * int) has been deleted already *)
walther@59619
   211
walther@59619
   212
(* used for calculating built in binary operations in Isabelle2002.
walther@59619
   213
   integer numerals n are ((n,0),(0,0)) i.e. precision is (0,0) *)
walther@59619
   214
fun calcul "Groups.plus_class.plus" ((a, b), _:int * int) ((c, d), _:int * int)  = (*FIXME.WN1008 drop Float.calc, var_op_float, float_op_var, term_of_float*)
walther@59619
   215
    if b < d 
walther@59619
   216
    then ((a + c * power 10 (d - b), b), (0, 0))(*FIXXXME precision*)
walther@59619
   217
    else ((a * power 10 (b - d) + c, d), (0, 0))(*FIXXXME precision*)
walther@59619
   218
  | calcul "Groups.minus_class.minus" ((a, 0), _) ((c, 0), _) =       (*FIXXXME float + prec.*)
walther@59619
   219
    ((a - c,0),(0,0))
walther@59619
   220
  | calcul "Groups.times_class.times" ((a, b), _) ((c, d), _) =       (*FIXXXME precision*)
walther@59619
   221
    ((a * c, b + d), (0, 0))
walther@59619
   222
  | calcul "Rings.divide_class.divide" ((a, 0), _) ((c, 0), _) = (*FIXXXME float + prec.*)
walther@59619
   223
    ((a div c, 0), (0, 0))
walther@59619
   224
  | calcul "Prog_Expr.pow" ((a, _), _) ((c, _), _) = (*FIXXXME Float + prec.*)
walther@59619
   225
    ((power a c, 0), (0, 0))
walther@59619
   226
  | calcul op_ ((a, b), (p11, p12)) ((c, d), (p21, p22)) = 
walther@59619
   227
    error ("calcul: not impl. for Float (("^
walther@59619
   228
		 (string_of_int a  )^","^(string_of_int b  )^"), ("^
walther@59619
   229
		 (string_of_int p11)^","^(string_of_int p12)^")) "^op_^" (("^
walther@59619
   230
		 (string_of_int c  )^","^(string_of_int d  )^"), ("^
walther@59619
   231
		 (string_of_int p21)^","^(string_of_int p22)^"))");
walther@59619
   232
(*> calcul "Groups.plus_class.plus" ((~1,0),(0,0)) ((2,0),(0,0)); 
walther@59619
   233
val it = ((1,0),(0,0))*)
walther@59619
   234
walther@59619
   235
(*.convert internal floatingpoint prepresentation to int and float.*)
walther@59619
   236
fun term_of_float T ((val1,    0), (         0,          0)) =
walther@59619
   237
    TermC.term_of_num T val1
walther@59619
   238
  | term_of_float T ((val1, val2), (precision1, precision2)) =
walther@59619
   239
    let val pT = TermC.pairT T T
walther@59619
   240
    in Const ("Float.Float", (TermC.pairT pT pT) --> T)
walther@59619
   241
	     $ (TermC.pairt (TermC.pairt (Free (TermC.str_of_int val1, T))
walther@59619
   242
			     (Free (TermC.str_of_int val2, T)))
walther@59619
   243
		      (TermC.pairt (Free (TermC.str_of_int precision1, T))
walther@59619
   244
			     (Free (TermC.str_of_int precision2, T))))
walther@59619
   245
    end;
walther@59619
   246
(*> val t = str2term "Float ((1,2),(0,0))";
walther@59619
   247
> val Const ("Float.Float", fT) $ _ = t;
walther@59619
   248
> atomtyp fT;
walther@59619
   249
> val ffT = (pairT (pairT HOLogic.realT HOLogic.realT) 
walther@59619
   250
> 	     (pairT HOLogic.realT HOLogic.realT)) --> HOLogic.realT;
walther@59619
   251
> atomtyp ffT;
walther@59619
   252
> fT = ffT;
walther@59619
   253
val it = true : bool
walther@59619
   254
walther@59619
   255
t = float_term_of_num HOLogic.realT ((1,2),(0,0));
walther@59619
   256
val it = true : bool*)
walther@59619
   257
walther@59619
   258
(*.assoc. convert internal floatingpoint prepresentation to int and float.*)
walther@59619
   259
fun var_op_float v op_ optype ntyp ((v1, 0), (0, 0)) =
walther@59619
   260
    TermC.mk_var_op_num v op_ optype ntyp v1
walther@59619
   261
  | var_op_float v op_ optype T ((v1, v2), (p1, p2)) =
walther@59619
   262
    let val pT = TermC.pairT T T
walther@59619
   263
    in Const (op_, optype) $ v $ 
walther@59619
   264
	     (Const ("Float.Float", (TermC.pairT pT pT) --> T)
walther@59619
   265
		    $ (TermC.pairt (TermC.pairt (Free (TermC.str_of_int v1, T))
walther@59619
   266
				    (Free (TermC.str_of_int v2, T)))
walther@59619
   267
			     (TermC.pairt (Free (TermC.str_of_int p1, T))
walther@59619
   268
				    (Free (TermC.str_of_int p2, T)))))
walther@59619
   269
    end;
walther@59619
   270
(*> val t = str2term "a + b";
walther@59619
   271
> val Const ("Groups.plus_class.plus", optype) $ _ $ _ = t;
walther@59619
   272
> val t = str2term "v + Float ((11,-1),(0,0))";val v = str2term "v";
walther@59619
   273
> t = var_op_float v "Groups.plus_class.plus" optype HOLogic.realT ((11,~1),(0,0));
walther@59619
   274
val it = true : bool*)
walther@59619
   275
walther@59619
   276
(*.assoc. convert internal floatingpoint prepresentation to int and float.*)
walther@59619
   277
fun float_op_var v op_ optype ntyp ((v1, 0), (0, 0)) =
walther@59619
   278
    TermC.mk_num_op_var v op_ optype ntyp v1
walther@59619
   279
  | float_op_var v op_ optype T ((v1, v2), (p1, p2)) =
walther@59619
   280
    let val pT = TermC.pairT T T
walther@59619
   281
    in Const (op_, optype) $ 
walther@59619
   282
	     (Const ("Float.Float", (TermC.pairT pT pT) --> T)
walther@59619
   283
		    $ (TermC.pairt (TermC.pairt (Free (TermC.str_of_int v1, T))
walther@59619
   284
				    (Free (TermC.str_of_int v2, T)))
walther@59619
   285
			     (TermC.pairt (Free (TermC.str_of_int p1, T))
walther@59619
   286
				    (Free (TermC.str_of_int p2, T))))) $ v
walther@59619
   287
    end;
walther@59619
   288
(*> val t = str2term "a + b";
walther@59619
   289
> val Const ("Groups.plus_class.plus", optype) $ _ $ _ = t;
walther@59619
   290
> val t = str2term "Float ((11,-1),(0,0)) + v";val v = str2term "v";
walther@59619
   291
> t = float_op_var v "Groups.plus_class.plus" optype HOLogic.realT ((11,~1),(0,0));
walther@59619
   292
val it = true : bool*)
walther@59619
   293
wneuper@59386
   294
end
neuper@37906
   295
neuper@37906
   296
neuper@37906
   297
neuper@37906
   298
neuper@37906
   299