Test_Isac works again, perfectly ..
# the same tests works as in 8df4b6196660 (the *child* of "Test_Isac works...")
# ..EXCEPT those marked with "exception Div raised"
# for general state of tests see Test_Isac section {* history of tests *}.
1 (* rationals, fractions of multivariate polynomials over the real field
3 Copyright (c) isac team 2002, 2013
4 Use is subject to license terms.
6 depends on Poly (and not on Atools), because
7 fractions with _normalized_ polynomials are canceled, added, etc.
11 imports Poly "~~/src/Tools/isac/Knowledge/GCD_Poly_ML"
14 section {* Constants for evaluation by "Calc" *}
17 is'_expanded :: "real => bool" ("_ is'_expanded") (*RL->Poly.thy*)
18 is'_ratpolyexp :: "real => bool" ("_ is'_ratpolyexp")
19 get_denominator :: "real => real"
20 get_numerator :: "real => real"
23 (*.the expression contains + - * ^ / only ?.*)
24 fun is_ratpolyexp (Free _) = true
25 | is_ratpolyexp (Const ("Groups.plus_class.plus",_) $ Free _ $ Free _) = true
26 | is_ratpolyexp (Const ("Groups.minus_class.minus",_) $ Free _ $ Free _) = true
27 | is_ratpolyexp (Const ("Groups.times_class.times",_) $ Free _ $ Free _) = true
28 | is_ratpolyexp (Const ("Atools.pow",_) $ Free _ $ Free _) = true
29 | is_ratpolyexp (Const ("Fields.inverse_class.divide",_) $ Free _ $ Free _) = true
30 | is_ratpolyexp (Const ("Groups.plus_class.plus",_) $ t1 $ t2) =
31 ((is_ratpolyexp t1) andalso (is_ratpolyexp t2))
32 | is_ratpolyexp (Const ("Groups.minus_class.minus",_) $ t1 $ t2) =
33 ((is_ratpolyexp t1) andalso (is_ratpolyexp t2))
34 | is_ratpolyexp (Const ("Groups.times_class.times",_) $ t1 $ t2) =
35 ((is_ratpolyexp t1) andalso (is_ratpolyexp t2))
36 | is_ratpolyexp (Const ("Atools.pow",_) $ t1 $ t2) =
37 ((is_ratpolyexp t1) andalso (is_ratpolyexp t2))
38 | is_ratpolyexp (Const ("Fields.inverse_class.divide",_) $ t1 $ t2) =
39 ((is_ratpolyexp t1) andalso (is_ratpolyexp t2))
40 | is_ratpolyexp _ = false;
42 (*("is_ratpolyexp", ("Rational.is'_ratpolyexp", eval_is_ratpolyexp ""))*)
43 fun eval_is_ratpolyexp (thmid:string) _
44 (t as (Const("Rational.is'_ratpolyexp", _) $ arg)) thy =
46 then SOME (mk_thmid thmid "" (term_to_string''' thy arg) "",
47 Trueprop $ (mk_equality (t, @{term True})))
48 else SOME (mk_thmid thmid "" (term_to_string''' thy arg) "",
49 Trueprop $ (mk_equality (t, @{term False})))
50 | eval_is_ratpolyexp _ _ _ _ = NONE;
52 (*("get_denominator", ("Rational.get_denominator", eval_get_denominator ""))*)
53 fun eval_get_denominator (thmid:string) _
54 (t as Const ("Rational.get_denominator", _) $
55 (Const ("Fields.inverse_class.divide", _) $ num $
57 SOME (mk_thmid thmid "" (term_to_string''' thy denom) "",
58 Trueprop $ (mk_equality (t, denom)))
59 | eval_get_denominator _ _ _ _ = NONE;
61 (*("get_numerator", ("Rational.get_numerator", eval_get_numerator ""))*)
62 fun eval_get_numerator (thmid:string) _
63 (t as Const ("Rational.get_numerator", _) $
64 (Const ("Fields.inverse_class.divide", _) $num
66 SOME (mk_thmid thmid "" (term_to_string''' thy num) "",
67 Trueprop $ (mk_equality (t, num)))
68 | eval_get_numerator _ _ _ _ = NONE;
71 section {* Theorems for rewriting *}
73 axiomatization (* naming due to Isabelle2002, but not contained in Isabelle2002;
74 many thms are due to RL and can be removed with updating the equation solver;
75 TODO: replace by equivalent thms in recent Isabelle201x *)
77 mult_cross: "[| b ~= 0; d ~= 0 |] ==> (a / b = c / d) = (a * d = b * c)" and
78 mult_cross1: " b ~= 0 ==> (a / b = c ) = (a = b * c)" and
79 mult_cross2: " d ~= 0 ==> (a = c / d) = (a * d = c)" and
81 add_minus: "a + b - b = a"(*RL->Poly.thy*) and
82 add_minus1: "a - b + b = a"(*RL->Poly.thy*) and
84 rat_mult: "a / b * (c / d) = a * c / (b * d)"(*?Isa02*) and
85 rat_mult2: "a / b * c = a * c / b "(*?Isa02*) and
87 rat_mult_poly_l: "c is_polyexp ==> c * (a / b) = c * a / b" and
88 rat_mult_poly_r: "c is_polyexp ==> (a / b) * c = a * c / b" and
90 (*real_times_divide1_eq .. Isa02*)
91 real_times_divide_1_eq: "-1 * (c / d) = -1 * c / d " and
92 real_times_divide_num: "a is_const ==> a * (c / d) = a * c / d " and
94 real_mult_div_cancel2: "k ~= 0 ==> m * k / (n * k) = m / n" and
95 (*real_mult_div_cancel1: "k ~= 0 ==> k * m / (k * n) = m / n"..Isa02*)
97 real_divide_divide1: "y ~= 0 ==> (u / v) / (y / z) = (u / v) * (z / y)" and
98 real_divide_divide1_mg: "y ~= 0 ==> (u / v) / (y / z) = (u * z) / (y * v)" and
99 (*real_divide_divide2_eq: "x / y / z = x / (y * z)"..Isa02*)
101 rat_power: "(a / b)^^^n = (a^^^n) / (b^^^n)" and
103 rat_add: "[| a is_const; b is_const; c is_const; d is_const |] ==>
104 a / c + b / d = (a * d + b * c) / (c * d)" and
105 rat_add_assoc: "[| a is_const; b is_const; c is_const; d is_const |] ==>
106 a / c +(b / d + e) = (a * d + b * c)/(d * c) + e" and
107 rat_add1: "[| a is_const; b is_const; c is_const |] ==>
108 a / c + b / c = (a + b) / c" and
109 rat_add1_assoc: "[| a is_const; b is_const; c is_const |] ==>
110 a / c + (b / c + e) = (a + b) / c + e" and
111 rat_add2: "[| a is_const; b is_const; c is_const |] ==>
112 a / c + b = (a + b * c) / c" and
113 rat_add2_assoc: "[| a is_const; b is_const; c is_const |] ==>
114 a / c + (b + e) = (a + b * c) / c + e" and
115 rat_add3: "[| a is_const; b is_const; c is_const |] ==>
116 a + b / c = (a * c + b) / c" and
117 rat_add3_assoc: "[| a is_const; b is_const; c is_const |] ==>
118 a + (b / c + e) = (a * c + b) / c + e"
120 section {* Cancellation and addition of fractions *}
121 subsection {* Conversion term <--> poly *}
122 subsubsection {* Convert a term to the internal representation of a multivariate polynomial *}
124 fun monom_of_term vs (c, es) (Free (id, _)) =
126 then (id |> int_of_str |> the |> curry op * c, es) (*several numerals in one monom*)
127 else (c, list_update es (find_index (curry op = id) vs) 1)
128 | monom_of_term vs (c, es) (Const ("Atools.pow", _) $ Free (id, _) $ Free (e, _)) =
129 (c, list_update es (find_index (curry op = id) vs) (the (int_of_str e)))
130 | monom_of_term vs (c, es) (Const ("Groups.times_class.times", _) $ m1 $ m2) =
131 let val (c', es') = monom_of_term vs (c, es) m1
132 in monom_of_term vs (c', es') m2 end
133 | monom_of_term _ _ t = raise ERROR ("poly malformed with " ^ term2str t)
135 fun monoms_of_term vs (t as Free _) =
136 [monom_of_term vs (1, replicate (length vs) 0) t]
137 | monoms_of_term vs (t as Const ("Atools.pow", _) $ _ $ _) =
138 [monom_of_term vs (1, replicate (length vs) 0) t]
139 | monoms_of_term vs (t as Const ("Groups.times_class.times", _) $ _ $ _) =
140 [monom_of_term vs (1, replicate (length vs) 0) t]
141 | monoms_of_term vs (Const ("Groups.plus_class.plus", _) $ ms1 $ ms2) =
142 (monoms_of_term vs ms1) @ (monoms_of_term vs ms2)
143 | monoms_of_term _ t = raise ERROR ("poly malformed with " ^ term2str t)
145 (* convert a term to the internal representation of a multivariate polynomial;
146 the conversion is quite liberal, see test --- fun poly_of_term ---:
147 * the order of variables and the parentheses within a monomial are arbitrary
148 * the coefficient may be somewhere
149 * he order and the parentheses within monomials are arbitrary
150 But the term must be completely expand + over * (laws of distributivity are not applicable).
152 The function requires the free variables as strings already given,
153 because the gcd involves 2 polynomials (with the same length for their list of exponents).
155 fun poly_of_term vs (t as Const ("Groups.plus_class.plus", _) $ _ $ _) =
156 (SOME (t |> monoms_of_term vs |> order)
157 handle ERROR _ => NONE)
158 | poly_of_term vs t =
159 (SOME [monom_of_term vs (1, replicate (length vs) 0) t]
160 handle ERROR _ => NONE)
164 val vs = t |> vars |> map str_of_free_opt (* tolerate Var in simplification *)
165 |> filter is_some |> map the |> sort string_ord
167 case poly_of_term vs t of SOME _ => true | NONE => false
169 val is_expanded = is_poly (* TODO: check names *)
170 val is_polynomial = is_poly (* TODO: check names *)
173 subsubsection {* Convert internal representation of a multivariate polynomial to a term *}
175 fun term_of_es _ _ _ [] = [] (*assumes same length for vs and es*)
176 | term_of_es baseT expT (_ :: vs) (0 :: es) =
177 [] @ term_of_es baseT expT vs es
178 | term_of_es baseT expT (v :: vs) (1 :: es) =
179 [(Free (v, baseT))] @ term_of_es baseT expT vs es
180 | term_of_es baseT expT (v :: vs) (e :: es) =
181 [Const ("Atools.pow", [baseT, expT] ---> baseT) $
182 (Free (v, baseT)) $ (Free (isastr_of_int e, expT))]
183 @ term_of_es baseT expT vs es
185 fun term_of_monom baseT expT vs ((c, es): monom) =
186 let val es' = term_of_es baseT expT vs es
190 if es' = [] (*if es = [0,0,0,...]*)
191 then Free (isastr_of_int c, baseT)
192 else foldl (HOLogic.mk_binop "Groups.times_class.times") (hd es', tl es')
193 else foldl (HOLogic.mk_binop "Groups.times_class.times") (Free (isastr_of_int c, baseT), es')
196 fun term_of_poly baseT expT vs p =
197 let val monos = map (term_of_monom baseT expT vs) p
198 in foldl (HOLogic.mk_binop "Groups.plus_class.plus") (hd monos, tl monos) end
201 subsection {* Apply gcd_poly for cancelling and adding fractions as terms *}
203 fun mk_noteq_0 baseT t =
204 Const ("HOL.Not", HOLogic.boolT --> HOLogic.boolT) $
205 (Const ("HOL.eq", [baseT, baseT] ---> HOLogic.boolT) $ t $ Free ("0", HOLogic.realT))
207 fun mk_asms baseT ts =
208 let val as' = filter_out is_num ts (* asm like "2 ~= 0" is needless *)
209 in map (mk_noteq_0 baseT) as' end
212 subsubsection {* Factor out gcd for cancellation *}
214 fun check_fraction t =
215 let val Const ("Fields.inverse_class.divide", _) $ numerator $ denominator = t
216 in SOME (numerator, denominator) end
219 (* prepare a term for cancellation by factoring out the gcd
220 assumes: is a fraction with outmost "/"*)
221 fun factout_p_ (thy: theory) t =
222 let val opt = check_fraction t
226 | SOME (numerator, denominator) =>
228 val vs = t |> vars |> map str_of_free_opt (* tolerate Var in simplification *)
229 |> filter is_some |> map the |> sort string_ord
230 val baseT = type_of numerator
231 val expT = HOLogic.realT
233 case (poly_of_term vs numerator, poly_of_term vs denominator) of
236 val ((a', b'), c) = gcd_poly a b
237 val es = replicate (length vs) 0
239 if c = [(1, es)] orelse c = [(~1, es)]
243 val b't = term_of_poly baseT expT vs b'
244 val ct = term_of_poly baseT expT vs c
246 HOLogic.mk_binop "Fields.inverse_class.divide"
247 (HOLogic.mk_binop "Groups.times_class.times"
248 (term_of_poly baseT expT vs a', ct),
249 HOLogic.mk_binop "Groups.times_class.times" (b't, ct))
250 in SOME (t', mk_asms baseT [b't, ct]) end
252 | _ => NONE : (term * term list) option
257 subsubsection {* Cancel a fraction *}
259 (* cancel a term by the gcd ("" denote terms with internal algebraic structure)
260 cancel_p_ :: theory \<Rightarrow> term \<Rightarrow> (term \<times> term list) option
261 cancel_p_ thy "a / b" = SOME ("a' / b'", ["b' \<noteq> 0"])
262 assumes: a is_polynomial \<and> b is_polynomial \<and> b \<noteq> 0
264 SOME ("a' / b'", ["b' \<noteq> 0"]). gcd_poly a b \<noteq> 1 \<and> gcd_poly a b \<noteq> -1 \<and>
265 a' * gcd_poly a b = a \<and> b' * gcd_poly a b = b
267 fun cancel_p_ (_: theory) t =
268 let val opt = check_fraction t
272 | SOME (numerator, denominator) =>
274 val vs = t |> vars |> map str_of_free_opt (* tolerate Var in simplification *)
275 |> filter is_some |> map the |> sort string_ord
276 val baseT = type_of numerator
277 val expT = HOLogic.realT
279 case (poly_of_term vs numerator, poly_of_term vs denominator) of
282 val ((a', b'), c) = gcd_poly a b
283 val es = replicate (length vs) 0
285 if c = [(1, es)] orelse c = [(~1, es)]
289 val bt' = term_of_poly baseT expT vs b'
290 val ct = term_of_poly baseT expT vs c
292 HOLogic.mk_binop "Fields.inverse_class.divide"
293 (term_of_poly baseT expT vs a', bt')
294 val asm = mk_asms baseT [bt']
295 in SOME (t', asm) end
297 | _ => NONE : (term * term list) option
302 subsubsection {* Factor out to a common denominator for addition *}
304 (* addition of fractions allows (at most) one non-fraction (a monomial) *)
306 (Const ("Groups.plus_class.plus", _) $
307 (Const ("Fields.inverse_class.divide", _) $ n1 $ d1) $
308 (Const ("Fields.inverse_class.divide", _) $ n2 $ d2))
309 = SOME ((n1, d1), (n2, d2))
311 (Const ("Groups.plus_class.plus", _) $
313 (Const ("Fields.inverse_class.divide", _) $ n2 $ d2))
314 = SOME ((nofrac, Free ("1", HOLogic.realT)), (n2, d2))
316 (Const ("Groups.plus_class.plus", _) $
317 (Const ("Fields.inverse_class.divide", _) $ n1 $ d1) $
319 = SOME ((n1, d1), (nofrac, Free ("1", HOLogic.realT)))
320 | check_frac_sum _ = NONE
322 (* prepare a term for addition by providing the least common denominator as a product
323 assumes: is a term with outmost "+" and at least one outmost "/" in respective summands*)
324 fun common_nominator_p_ (_: theory) t =
325 let val opt = check_frac_sum t
329 | SOME ((n1, d1), (n2, d2)) =>
331 val vs = t |> vars |> map str_of_free_opt (* tolerate Var in simplification *)
332 |> filter is_some |> map the |> sort string_ord
334 case (poly_of_term vs d1, poly_of_term vs d2) of
337 val ((a', b'), c) = gcd_poly a b
338 val (baseT, expT) = (type_of n1, HOLogic.realT)
339 val [d1', d2', c'] = map (term_of_poly baseT expT vs) [a', b', c]
340 (*----- minimum of parentheses & nice result, but breaks tests: -------------
341 val denom = HOLogic.mk_binop "Groups.times_class.times"
342 (HOLogic.mk_binop "Groups.times_class.times" (d1', d2'), c') -------------*)
344 if c = [(1, replicate (length vs) 0)]
345 then HOLogic.mk_binop "Groups.times_class.times" (d1', d2')
347 HOLogic.mk_binop "Groups.times_class.times" (c',
348 HOLogic.mk_binop "Groups.times_class.times" (d1', d2')) (*--------------*)
350 HOLogic.mk_binop "Groups.plus_class.plus"
351 (HOLogic.mk_binop "Fields.inverse_class.divide"
352 (HOLogic.mk_binop "Groups.times_class.times" (n1, d2'), denom),
353 HOLogic.mk_binop "Fields.inverse_class.divide"
354 (HOLogic.mk_binop "Groups.times_class.times" (n2, d1'), denom))
355 val asm = mk_asms baseT [d1', d2', c']
356 in SOME (t', asm) end
357 | _ => NONE : (term * term list) option
363 subsubsection {* Addition of at least one fraction within a sum *}
366 assumes: is a term with outmost "+" and at least one outmost "/" in respective summands
367 NOTE: the case "(_ + _) + _" need not be considered due to iterated addition.*)
368 fun add_fraction_p_ (_: theory) t =
369 case check_frac_sum t of
371 | SOME ((n1, d1), (n2, d2)) =>
373 val vs = t |> vars |> map str_of_free_opt (* tolerate Var in simplification *)
374 |> filter is_some |> map the |> sort string_ord
376 case (poly_of_term vs n1, poly_of_term vs d1, poly_of_term vs n2, poly_of_term vs d2) of
377 (SOME _, SOME a, SOME _, SOME b) =>
379 val ((a', b'), c) = gcd_poly a b
380 val (baseT, expT) = (type_of n1, HOLogic.realT)
381 val nomin = term_of_poly baseT expT vs
382 (((the (poly_of_term vs n1)) %%*%% b') %%+%% ((the (poly_of_term vs n2)) %%*%% a'))
383 val denom = term_of_poly baseT expT vs ((c %%*%% a') %%*%% b')
384 val t' = HOLogic.mk_binop "Fields.inverse_class.divide" (nomin, denom)
385 in SOME (t', mk_asms baseT [denom]) end
386 | _ => NONE : (term * term list) option
390 section {* Embed cancellation and addition into rewriting *}
391 ML {* val thy = @{theory} *}
392 subsection {* Rulesets and predicate for embedding *}
394 (* evaluates conditions in calculate_Rational *)
397 (Rls {id = "calc_rat_erls", preconds = [], rew_ord = ("dummy_ord", dummy_ord),
398 erls = e_rls, srls = Erls, calc = [], errpatts = [],
400 [Calc ("HOL.eq", eval_equal "#equal_"),
401 Calc ("Atools.is'_const", eval_const "#is_const_"),
402 Thm ("not_true", num_str @{thm not_true}),
403 Thm ("not_false", num_str @{thm not_false})],
406 (* simplifies expressions with numerals;
407 does NOT rearrange the term by AC-rewriting; thus terms with variables
408 need to have constants to be commuted together respectively *)
409 val calculate_Rational =
410 prep_rls (merge_rls "calculate_Rational"
411 (Rls {id = "divide", preconds = [], rew_ord = ("dummy_ord", dummy_ord),
412 erls = calc_rat_erls, srls = Erls,
413 calc = [], errpatts = [],
415 [Calc ("Fields.inverse_class.divide", eval_cancel "#divide_e"),
417 Thm ("minus_divide_left", num_str (@{thm minus_divide_left} RS @{thm sym})),
418 (*SYM - ?x / ?y = - (?x / ?y) may come from subst*)
419 Thm ("rat_add", num_str @{thm rat_add}),
420 (*"[| a is_const; b is_const; c is_const; d is_const |] ==> \
421 \a / c + b / d = (a * d) / (c * d) + (b * c ) / (d * c)"*)
422 Thm ("rat_add1", num_str @{thm rat_add1}),
423 (*"[| a is_const; b is_const; c is_const |] ==> a / c + b / c = (a + b) / c"*)
424 Thm ("rat_add2", num_str @{thm rat_add2}),
425 (*"[| ?a is_const; ?b is_const; ?c is_const |] ==> ?a / ?c + ?b = (?a + ?b * ?c) / ?c"*)
426 Thm ("rat_add3", num_str @{thm rat_add3}),
427 (*"[| a is_const; b is_const; c is_const |] ==> a + b / c = (a * c) / c + b / c"\
428 .... is_const to be omitted here FIXME*)
430 Thm ("rat_mult", num_str @{thm rat_mult}),
431 (*a / b * (c / d) = a * c / (b * d)*)
432 Thm ("times_divide_eq_right", num_str @{thm times_divide_eq_right}),
433 (*?x * (?y / ?z) = ?x * ?y / ?z*)
434 Thm ("times_divide_eq_left", num_str @{thm times_divide_eq_left}),
435 (*?y / ?z * ?x = ?y * ?x / ?z*)
437 Thm ("real_divide_divide1", num_str @{thm real_divide_divide1}),
438 (*"?y ~= 0 ==> ?u / ?v / (?y / ?z) = ?u / ?v * (?z / ?y)"*)
439 Thm ("divide_divide_eq_left", num_str @{thm divide_divide_eq_left}),
440 (*"?x / ?y / ?z = ?x / (?y * ?z)"*)
442 Thm ("rat_power", num_str @{thm rat_power}),
443 (*"(?a / ?b) ^^^ ?n = ?a ^^^ ?n / ?b ^^^ ?n"*)
445 Thm ("mult_cross", num_str @{thm mult_cross}),
446 (*"[| b ~= 0; d ~= 0 |] ==> (a / b = c / d) = (a * d = b * c)*)
447 Thm ("mult_cross1", num_str @{thm mult_cross1}),
448 (*" b ~= 0 ==> (a / b = c ) = (a = b * c)*)
449 Thm ("mult_cross2", num_str @{thm mult_cross2})
450 (*" d ~= 0 ==> (a = c / d) = (a * d = c)*)],
454 (*("is_expanded", ("Rational.is'_expanded", eval_is_expanded ""))*)
455 fun eval_is_expanded (thmid:string) _
456 (t as (Const("Rational.is'_expanded", _) $ arg)) thy =
458 then SOME (mk_thmid thmid "" (term_to_string''' thy arg) "",
459 Trueprop $ (mk_equality (t, @{term True})))
460 else SOME (mk_thmid thmid "" (term_to_string''' thy arg) "",
461 Trueprop $ (mk_equality (t, @{term False})))
462 | eval_is_expanded _ _ _ _ = NONE;
464 calclist':= overwritel (!calclist',
465 [("is_expanded", ("Rational.is'_expanded", eval_is_expanded ""))]);
468 merge_rls "rational_erls" calculate_Rational
469 (append_rls "is_expanded" Atools_erls
470 [Calc ("Rational.is'_expanded", eval_is_expanded "")]);
473 subsection {* Embed cancellation into rewriting *}
477 val {rules = rules, rew_ord = (_, ro), ...} = rep_rls (assoc_rls "rev_rew_p");
479 fun init_state thy eval_rls ro t =
481 val SOME (t', _) = factout_p_ thy t;
482 val SOME (t'', asm) = cancel_p_ thy t;
483 val der = reverse_deriv thy eval_rls rules ro NONE t';
485 [(Thm ("real_mult_div_cancel2", num_str @{thm real_mult_div_cancel2}), (t'', asm))]
486 val rs = (distinct_Thm o (map #1)) der
487 val rs = filter_out (eq_Thms
488 ["sym_real_add_zero_left", "sym_real_mult_0", "sym_real_mult_1"]) rs
489 in (t, t'', [rs(*one in order to ease locate_rule*)], der) end;
491 fun locate_rule thy eval_rls ro [rs] t r =
492 if member op = ((map (id_of_thm)) rs) (id_of_thm r)
494 let val ropt = rewrite_ thy ro eval_rls true (thm_of_thm r) t;
496 case ropt of SOME ta => [(r, ta)]
498 ("### locate_rule: rewrite " ^ id_of_thm r ^ " " ^ term2str t ^ " = NONE"); [])
500 else (tracing ("### locate_rule: " ^ id_of_thm r ^ " not mem rrls"); [])
501 | locate_rule _ _ _ _ _ _ = error "locate_rule: doesnt match rev-sets in istate";
503 fun next_rule thy eval_rls ro [rs] t =
505 val der = make_deriv thy eval_rls rs ro NONE t;
506 in case der of (_, r, _) :: _ => SOME r | _ => NONE end
507 | next_rule _ _ _ _ _ = error ("next_rule: doesnt match rev-sets in istate");
509 fun attach_form (_:rule list list) (_:term) (_:term) =
510 [(*TODO*)]: (rule * (term * term list)) list;
515 Rrls {id = "cancel_p", prepat = [],
516 rew_ord=("ord_make_polynomial", ord_make_polynomial false thy),
517 erls = rational_erls,
519 [("PLUS", ("Groups.plus_class.plus", eval_binop "#add_")),
520 ("TIMES" , ("Groups.times_class.times", eval_binop "#mult_")),
521 ("DIVIDE", ("Fields.inverse_class.divide", eval_cancel "#divide_e")),
522 ("POWER", ("Atools.pow", eval_binop "#power_"))],
525 Rfuns {init_state = init_state thy Atools_erls ro,
526 normal_form = cancel_p_ thy,
527 locate_rule = locate_rule thy Atools_erls ro,
528 next_rule = next_rule thy Atools_erls ro,
529 attach_form = attach_form}}
530 end; (* local cancel_p *)
533 subsection {* Embed addition into rewriting *}
535 local (* add_fractions_p *)
537 val {rules = rules, rew_ord = (_, ro), ...} = rep_rls (assoc_rls "make_polynomial");
538 val {rules, rew_ord=(_,ro),...} = rep_rls (assoc_rls "rev_rew_p");
540 fun init_state thy eval_rls ro t =
542 val SOME (t',_) = common_nominator_p_ thy t;
543 val SOME (t'', asm) = add_fraction_p_ thy t;
544 val der = reverse_deriv thy eval_rls rules ro NONE t';
546 [(Thm ("real_mult_div_cancel2", num_str @{thm real_mult_div_cancel2}), (t'',asm))]
547 val rs = (distinct_Thm o (map #1)) der;
548 val rs = filter_out (eq_Thms
549 ["sym_real_add_zero_left", "sym_real_mult_0", "sym_real_mult_1"]) rs;
550 in (t, t'', [rs(*here only _ONE_*)], der) end;
552 fun locate_rule thy eval_rls ro [rs] t r =
553 if member op = ((map (id_of_thm)) rs) (id_of_thm r)
555 let val ropt = rewrite_ thy ro eval_rls true (thm_of_thm r) t;
560 (tracing ("### locate_rule: rewrite " ^ id_of_thm r ^ " " ^ term2str t ^ " = NONE");
562 else (tracing ("### locate_rule: " ^ id_of_thm r ^ " not mem rrls"); [])
563 | locate_rule _ _ _ _ _ _ = error "locate_rule: doesnt match rev-sets in istate";
565 fun next_rule thy eval_rls ro [rs] t =
566 let val der = make_deriv thy eval_rls rs ro NONE t;
572 | next_rule _ _ _ _ _ = error ("next_rule: doesnt match rev-sets in istate");
574 val pat0 = parse_patt thy "?r/?s+?u/?v :: real";
575 val pat1 = parse_patt thy "?r/?s+?u :: real";
576 val pat2 = parse_patt thy "?r +?u/?v :: real";
577 val prepat = [([@{term True}], pat0),
578 ([@{term True}], pat1),
579 ([@{term True}], pat2)];
582 val add_fractions_p =
583 Rrls {id = "add_fractions_p", prepat=prepat,
584 rew_ord = ("ord_make_polynomial", ord_make_polynomial false thy),
585 erls = rational_erls,
586 calc = [("PLUS", ("Groups.plus_class.plus", eval_binop "#add_")),
587 ("TIMES", ("Groups.times_class.times", eval_binop "#mult_")),
588 ("DIVIDE", ("Fields.inverse_class.divide", eval_cancel "#divide_e")),
589 ("POWER", ("Atools.pow", eval_binop "#power_"))],
591 scr = Rfuns {init_state = init_state thy Atools_erls ro,
592 normal_form = add_fraction_p_ thy,
593 locate_rule = locate_rule thy Atools_erls ro,
594 next_rule = next_rule thy Atools_erls ro,
595 attach_form = attach_form}}
596 end; (*local add_fractions_p *)
599 subsection {* Cancelling and adding all occurrences in a term /////////////////////////////*}
601 (*copying cancel_p_rls + add her caused error in interface.sml*)
604 section {* Rulesets for general simplification *}
607 (*-------------------18.3.03 --> struct <-----------vvv--
608 val add_fractions_p = common_nominator_p; (*FIXXXME:eilig f"ur norm_Rational*)
609 -------------------18.3.03 --> struct <-----------vvv--*)
611 (*erls for calculate_Rational; make local with FIXX@ME result:term *term list*)
612 val powers_erls = prep_rls(
613 Rls {id = "powers_erls", preconds = [], rew_ord = ("dummy_ord",dummy_ord),
614 erls = e_rls, srls = Erls, calc = [], errpatts = [],
615 rules = [Calc ("Atools.is'_atom",eval_is_atom "#is_atom_"),
616 Calc ("Atools.is'_even",eval_is_even "#is_even_"),
617 Calc ("Orderings.ord_class.less",eval_equ "#less_"),
618 Thm ("not_false", num_str @{thm not_false}),
619 Thm ("not_true", num_str @{thm not_true}),
620 Calc ("Groups.plus_class.plus",eval_binop "#add_")
624 (*.all powers over + distributed; atoms over * collected, other distributed
625 contains absolute minimum of thms for context in norm_Rational .*)
626 val powers = prep_rls(
627 Rls {id = "powers", preconds = [], rew_ord = ("dummy_ord",dummy_ord),
628 erls = powers_erls, srls = Erls, calc = [], errpatts = [],
629 rules = [Thm ("realpow_multI", num_str @{thm realpow_multI}),
630 (*"(r * s) ^^^ n = r ^^^ n * s ^^^ n"*)
631 Thm ("realpow_pow",num_str @{thm realpow_pow}),
632 (*"(a ^^^ b) ^^^ c = a ^^^ (b * c)"*)
633 Thm ("realpow_oneI",num_str @{thm realpow_oneI}),
635 Thm ("realpow_minus_even",num_str @{thm realpow_minus_even}),
636 (*"n is_even ==> (- r) ^^^ n = r ^^^ n" ?-->discard_minus?*)
637 Thm ("realpow_minus_odd",num_str @{thm realpow_minus_odd}),
638 (*"Not (n is_even) ==> (- r) ^^^ n = -1 * r ^^^ n"*)
640 (*----- collect atoms over * -----*)
641 Thm ("realpow_two_atom",num_str @{thm realpow_two_atom}),
642 (*"r is_atom ==> r * r = r ^^^ 2"*)
643 Thm ("realpow_plus_1",num_str @{thm realpow_plus_1}),
644 (*"r is_atom ==> r * r ^^^ n = r ^^^ (n + 1)"*)
645 Thm ("realpow_addI_atom",num_str @{thm realpow_addI_atom}),
646 (*"r is_atom ==> r ^^^ n * r ^^^ m = r ^^^ (n + m)"*)
648 (*----- distribute none-atoms -----*)
649 Thm ("realpow_def_atom",num_str @{thm realpow_def_atom}),
650 (*"[| 1 < n; not(r is_atom) |]==>r ^^^ n = r * r ^^^ (n + -1)"*)
651 Thm ("realpow_eq_oneI",num_str @{thm realpow_eq_oneI}),
653 Calc ("Groups.plus_class.plus",eval_binop "#add_")
657 (*.contains absolute minimum of thms for context in norm_Rational.*)
658 val rat_mult_divide = prep_rls(
659 Rls {id = "rat_mult_divide", preconds = [],
660 rew_ord = ("dummy_ord", dummy_ord),
661 erls = e_rls, srls = Erls, calc = [], errpatts = [],
662 rules = [Thm ("rat_mult",num_str @{thm rat_mult}),
663 (*(1)"?a / ?b * (?c / ?d) = ?a * ?c / (?b * ?d)"*)
664 Thm ("times_divide_eq_right",num_str @{thm times_divide_eq_right}),
665 (*(2)"?a * (?c / ?d) = ?a * ?c / ?d" must be [2],
666 otherwise inv.to a / b / c = ...*)
667 Thm ("times_divide_eq_left",num_str @{thm times_divide_eq_left}),
668 (*"?a / ?b * ?c = ?a * ?c / ?b" order weights x^^^n too much
669 and does not commute a / b * c ^^^ 2 !*)
671 Thm ("divide_divide_eq_right",
672 num_str @{thm divide_divide_eq_right}),
673 (*"?x / (?y / ?z) = ?x * ?z / ?y"*)
674 Thm ("divide_divide_eq_left",
675 num_str @{thm divide_divide_eq_left}),
676 (*"?x / ?y / ?z = ?x / (?y * ?z)"*)
677 Calc ("Fields.inverse_class.divide" ,eval_cancel "#divide_e")
682 (*.contains absolute minimum of thms for context in norm_Rational.*)
683 val reduce_0_1_2 = prep_rls(
684 Rls{id = "reduce_0_1_2", preconds = [], rew_ord = ("dummy_ord", dummy_ord),
685 erls = e_rls, srls = Erls, calc = [], errpatts = [],
686 rules = [(*Thm ("divide_1",num_str @{thm divide_1}),
687 "?x / 1 = ?x" unnecess.for normalform*)
688 Thm ("mult_1_left",num_str @{thm mult_1_left}),
690 (*Thm ("real_mult_minus1",num_str @{thm real_mult_minus1}),
692 (*Thm ("real_minus_mult_cancel",num_str @{thm real_minus_mult_cancel}),
693 "- ?x * - ?y = ?x * ?y"*)
695 Thm ("mult_zero_left",num_str @{thm mult_zero_left}),
697 Thm ("add_0_left",num_str @{thm add_0_left}),
699 (*Thm ("right_minus",num_str @{thm right_minus}),
702 Thm ("sym_real_mult_2",
703 num_str (@{thm real_mult_2} RS @{thm sym})),
704 (*"z1 + z1 = 2 * z1"*)
705 Thm ("real_mult_2_assoc",num_str @{thm real_mult_2_assoc}),
706 (*"z1 + (z1 + k) = 2 * z1 + k"*)
708 Thm ("divide_zero_left",num_str @{thm divide_zero_left})
710 ], scr = EmptyScr}:rls);
712 (*erls for calculate_Rational;
713 make local with FIXX@ME result:term *term list WN0609???SKMG*)
714 val norm_rat_erls = prep_rls(
715 Rls {id = "norm_rat_erls", preconds = [], rew_ord = ("dummy_ord",dummy_ord),
716 erls = e_rls, srls = Erls, calc = [], errpatts = [],
717 rules = [Calc ("Atools.is'_const",eval_const "#is_const_")
718 ], scr = EmptyScr}:rls);
720 (* consists of rls containing the absolute minimum of thms *)
721 (*040209: this version has been used by RL for his equations,
722 which is now replaced by MGs version "norm_Rational" below *)
723 val norm_Rational_min = prep_rls(
724 Rls {id = "norm_Rational_min", preconds = [], rew_ord = ("dummy_ord",dummy_ord),
725 erls = norm_rat_erls, srls = Erls, calc = [], errpatts = [],
726 rules = [(*sequence given by operator precedence*)
729 Rls_ rat_mult_divide,
733 Rls_ collect_numerals,
734 Rls_ add_fractions_p,
737 scr = EmptyScr}:rls);
739 val norm_Rational_parenthesized = prep_rls(
740 Seq {id = "norm_Rational_parenthesized", preconds = []:term list,
741 rew_ord = ("dummy_ord", dummy_ord),
742 erls = Atools_erls, srls = Erls,
743 calc = [], errpatts = [],
744 rules = [Rls_ norm_Rational_min,
745 Rls_ discard_parentheses
747 scr = EmptyScr}:rls);
749 (*WN030318???SK: simplifies all but cancel and common_nominator*)
750 val simplify_rational =
751 merge_rls "simplify_rational" expand_binoms
752 (append_rls "divide" calculate_Rational
753 [Thm ("divide_1",num_str @{thm divide_1}),
755 Thm ("rat_mult",num_str @{thm rat_mult}),
756 (*(1)"?a / ?b * (?c / ?d) = ?a * ?c / (?b * ?d)"*)
757 Thm ("times_divide_eq_right",num_str @{thm times_divide_eq_right}),
758 (*(2)"?a * (?c / ?d) = ?a * ?c / ?d" must be [2],
759 otherwise inv.to a / b / c = ...*)
760 Thm ("times_divide_eq_left",num_str @{thm times_divide_eq_left}),
761 (*"?a / ?b * ?c = ?a * ?c / ?b"*)
762 Thm ("add_minus",num_str @{thm add_minus}),
763 (*"?a + ?b - ?b = ?a"*)
764 Thm ("add_minus1",num_str @{thm add_minus1}),
765 (*"?a - ?b + ?b = ?a"*)
766 Thm ("divide_minus1",num_str @{thm divide_minus1})
771 val add_fractions_p_rls = prep_rls(
772 Rls {id = "add_fractions_p_rls", preconds = [], rew_ord = ("dummy_ord", dummy_ord),
773 erls = e_rls, srls = Erls, calc = [], errpatts = [],
774 rules = [Rls_ add_fractions_p],
777 (* "Rls" causes repeated application of cancel_p to one and the same term *)
778 val cancel_p_rls = prep_rls(
780 {id = "cancel_p_rls", preconds = [], rew_ord = ("dummy_ord", dummy_ord),
781 erls = e_rls, srls = Erls, calc = [], errpatts = [],
782 rules = [Rls_ cancel_p],
785 (*. makes 'normal' fractions; 'is_polyexp' inhibits double fractions;
786 used in initial part norm_Rational_mg, see example DA-M02-main.p.60.*)
787 val rat_mult_poly = prep_rls(
788 Rls {id = "rat_mult_poly", preconds = [], rew_ord = ("dummy_ord", dummy_ord),
789 erls = append_rls "e_rls-is_polyexp" e_rls [Calc ("Poly.is'_polyexp", eval_is_polyexp "")],
790 srls = Erls, calc = [], errpatts = [],
792 [Thm ("rat_mult_poly_l",num_str @{thm rat_mult_poly_l}),
793 (*"?c is_polyexp ==> ?c * (?a / ?b) = ?c * ?a / ?b"*)
794 Thm ("rat_mult_poly_r",num_str @{thm rat_mult_poly_r})
795 (*"?c is_polyexp ==> ?a / ?b * ?c = ?a * ?c / ?b"*) ],
798 (*. makes 'normal' fractions; 'is_polyexp' inhibits double fractions;
799 used in looping part norm_Rational_rls, see example DA-M02-main.p.60
800 .. WHERE THE LATTER DOES ALWAYS WORK, BECAUSE erls = e_rls,
801 I.E. THE RESPECTIVE ASSUMPTION IS STORED AND Thm APPLIED; WN051028
803 val rat_mult_div_pow = prep_rls(
804 Rls {id = "rat_mult_div_pow", preconds = [], rew_ord = ("dummy_ord",dummy_ord),
805 erls = e_rls, srls = Erls, calc = [], errpatts = [],
806 rules = [Thm ("rat_mult", num_str @{thm rat_mult}),
807 (*"?a / ?b * (?c / ?d) = ?a * ?c / (?b * ?d)"*)
808 Thm ("rat_mult_poly_l", num_str @{thm rat_mult_poly_l}),
809 (*"?c is_polyexp ==> ?c * (?a / ?b) = ?c * ?a / ?b"*)
810 Thm ("rat_mult_poly_r", num_str @{thm rat_mult_poly_r}),
811 (*"?c is_polyexp ==> ?a / ?b * ?c = ?a * ?c / ?b"*)
813 Thm ("real_divide_divide1_mg", num_str @{thm real_divide_divide1_mg}),
814 (*"y ~= 0 ==> (u / v) / (y / z) = (u * z) / (y * v)"*)
815 Thm ("divide_divide_eq_right", num_str @{thm divide_divide_eq_right}),
816 (*"?x / (?y / ?z) = ?x * ?z / ?y"*)
817 Thm ("divide_divide_eq_left", num_str @{thm divide_divide_eq_left}),
818 (*"?x / ?y / ?z = ?x / (?y * ?z)"*)
819 Calc ("Fields.inverse_class.divide", eval_cancel "#divide_e"),
821 Thm ("rat_power", num_str @{thm rat_power})
822 (*"(?a / ?b) ^^^ ?n = ?a ^^^ ?n / ?b ^^^ ?n"*)
824 scr = EmptyScr}:rls);
826 val rat_reduce_1 = prep_rls(
827 Rls {id = "rat_reduce_1", preconds = [], rew_ord = ("dummy_ord", dummy_ord),
828 erls = e_rls, srls = Erls, calc = [], errpatts = [],
830 [Thm ("divide_1", num_str @{thm divide_1}),
832 Thm ("mult_1_left", num_str @{thm mult_1_left})
835 scr = EmptyScr}:rls);
837 (* looping part of norm_Rational *)
838 val norm_Rational_rls = prep_rls (
839 Rls {id = "norm_Rational_rls", preconds = [], rew_ord = ("dummy_ord",dummy_ord),
840 erls = norm_rat_erls, srls = Erls, calc = [], errpatts = [],
841 rules = [Rls_ add_fractions_p_rls,
842 Rls_ rat_mult_div_pow,
843 Rls_ make_rat_poly_with_parentheses,
847 scr = EmptyScr}:rls);
849 val norm_Rational = prep_rls (
851 {id = "norm_Rational", preconds = [], rew_ord = ("dummy_ord", dummy_ord),
852 erls = norm_rat_erls, srls = Erls, calc = [], errpatts = [],
853 rules = [Rls_ discard_minus,
854 Rls_ rat_mult_poly, (* removes double fractions like a/b/c *)
855 Rls_ make_rat_poly_with_parentheses,
857 Rls_ norm_Rational_rls, (* the main rls, looping (#) *)
858 Rls_ discard_parentheses1 (* mult only *)
860 scr = EmptyScr}:rls);
863 ruleset' := overwritelthy @{theory} (!ruleset',
864 [("calculate_Rational", calculate_Rational),
865 ("calc_rat_erls",calc_rat_erls),
866 ("rational_erls", rational_erls),
867 ("cancel_p", cancel_p),
868 ("add_fractions_p", add_fractions_p),
869 ("add_fractions_p_rls", add_fractions_p_rls),
870 (*WN120410 ("discard_minus", discard_minus), is defined in Poly.thy*)
871 ("powers_erls", powers_erls),
873 ("rat_mult_divide", rat_mult_divide),
874 ("reduce_0_1_2", reduce_0_1_2),
875 ("rat_reduce_1", rat_reduce_1),
876 ("norm_rat_erls", norm_rat_erls),
877 ("norm_Rational", norm_Rational),
878 ("norm_Rational_rls", norm_Rational_rls),
879 ("norm_Rational_parenthesized", norm_Rational_parenthesized),
880 ("rat_mult_poly", rat_mult_poly),
881 ("rat_mult_div_pow", rat_mult_div_pow),
882 ("cancel_p_rls", cancel_p_rls)
887 section {* A problem for simplification of rationals *}
890 (prep_pbt thy "pbl_simp_rat" [] e_pblID
891 (["rational","simplification"],
892 [("#Given" ,["Term t_t"]),
893 ("#Where" ,["t_t is_ratpolyexp"]),
894 ("#Find" ,["normalform n_n"])
896 append_rls "e_rls" e_rls [(*for preds in where_*)],
898 [["simplification","of_rationals"]]));
901 section {* A methods for simplification of rationals *}
903 (*WN061025 this methods script is copied from (auto-generated) script
904 of norm_Rational in order to ease repair on inform*)
905 store_met (prep_met thy "met_simp_rat" [] e_metID (["simplification","of_rationals"],
906 [("#Given" ,["Term t_t"]),
907 ("#Where" ,["t_t is_ratpolyexp"]),
908 ("#Find" ,["normalform n_n"])],
909 {rew_ord'="tless_true", rls' = e_rls, calc = [], srls = e_rls,
910 prls = append_rls "simplification_of_rationals_prls" e_rls
911 [(*for preds in where_*) Calc ("Rational.is'_ratpolyexp", eval_is_ratpolyexp "")],
912 crls = e_rls, errpats = [],
913 nrls = norm_Rational_rls},
914 "Script SimplifyScript (t_t::real) = " ^
915 " ((Try (Rewrite_Set discard_minus False) @@ " ^
916 " Try (Rewrite_Set rat_mult_poly False) @@ " ^
917 " Try (Rewrite_Set make_rat_poly_with_parentheses False) @@ " ^
918 " Try (Rewrite_Set cancel_p_rls False) @@ " ^
920 " ((Try (Rewrite_Set add_fractions_p_rls False) @@ " ^
921 " Try (Rewrite_Set rat_mult_div_pow False) @@ " ^
922 " Try (Rewrite_Set make_rat_poly_with_parentheses False) @@" ^
923 " Try (Rewrite_Set cancel_p_rls False) @@ " ^
924 " Try (Rewrite_Set rat_reduce_1 False)))) @@ " ^
925 " Try (Rewrite_Set discard_parentheses1 False)) " ^