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 |
|