30 |
30 |
31 fun dest_binary ct ct' = |
31 fun dest_binary ct ct' = |
32 if is_binop ct ct' then Thm.dest_binop ct' |
32 if is_binop ct ct' then Thm.dest_binop ct' |
33 else raise CTERM ("dest_binary: bad binop", [ct, ct']) |
33 else raise CTERM ("dest_binary: bad binop", [ct, ct']) |
34 |
34 |
35 val rat_0 = Rat.zero; |
|
36 val rat_1 = Rat.one; |
|
37 val minus_rat = Rat.neg; |
35 val minus_rat = Rat.neg; |
38 val denominator_rat = Rat.dest #> snd #> Rat.of_int; |
36 val denominator_rat = Rat.dest #> snd #> Rat.of_int; |
39 fun int_of_rat a = |
37 fun int_of_rat a = |
40 case Rat.dest a of (i,1) => i | _ => error "int_of_rat: not an int"; |
38 case Rat.dest a of (i,1) => i | _ => error "int_of_rat: not an int"; |
41 val lcm_rat = fn x => fn y => Rat.of_int (Integer.lcm (int_of_rat x) (int_of_rat y)); |
39 val lcm_rat = fn x => fn y => Rat.of_int (Integer.lcm (int_of_rat x) (int_of_rat y)); |
79 ([],l2) => l2 |
77 ([],l2) => l2 |
80 | (l1,[]) => l1 |
78 | (l1,[]) => l1 |
81 | ((c1,m1)::o1,(c2,m2)::o2) => |
79 | ((c1,m1)::o1,(c2,m2)::o2) => |
82 if m1 = m2 then |
80 if m1 = m2 then |
83 let val c = c1 + c2 val rest = grob_add o1 o2 in |
81 let val c = c1 + c2 val rest = grob_add o1 o2 in |
84 if c = rat_0 then rest else (c,m1)::rest end |
82 if c = @0 then rest else (c,m1)::rest end |
85 else if morder_lt m2 m1 then (c1,m1)::(grob_add o1 l2) |
83 else if morder_lt m2 m1 then (c1,m1)::(grob_add o1 l2) |
86 else (c2,m2)::(grob_add l1 o2); |
84 else (c2,m2)::(grob_add l1 o2); |
87 |
85 |
88 fun grob_sub l1 l2 = grob_add l1 (grob_neg l2); |
86 fun grob_sub l1 l2 = grob_add l1 (grob_neg l2); |
89 |
87 |
97 | (h1::t1) => grob_add (grob_cmul h1 l2) (grob_mul t1 l2); |
95 | (h1::t1) => grob_add (grob_cmul h1 l2) (grob_mul t1 l2); |
98 |
96 |
99 fun grob_inv l = |
97 fun grob_inv l = |
100 case l of |
98 case l of |
101 [(c,vs)] => if (forall (fn x => x = 0) vs) then |
99 [(c,vs)] => if (forall (fn x => x = 0) vs) then |
102 if (c = rat_0) then error "grob_inv: division by zero" |
100 if c = @0 then error "grob_inv: division by zero" |
103 else [(rat_1 / c,vs)] |
101 else [(@1 / c,vs)] |
104 else error "grob_inv: non-constant divisor polynomial" |
102 else error "grob_inv: non-constant divisor polynomial" |
105 | _ => error "grob_inv: non-constant divisor polynomial"; |
103 | _ => error "grob_inv: non-constant divisor polynomial"; |
106 |
104 |
107 fun grob_div l1 l2 = |
105 fun grob_div l1 l2 = |
108 case l2 of |
106 case l2 of |
109 [(c,l)] => if (forall (fn x => x = 0) l) then |
107 [(c,l)] => if (forall (fn x => x = 0) l) then |
110 if c = rat_0 then error "grob_div: division by zero" |
108 if c = @0 then error "grob_div: division by zero" |
111 else grob_cmul (rat_1 / c,l) l1 |
109 else grob_cmul (@1 / c,l) l1 |
112 else error "grob_div: non-constant divisor polynomial" |
110 else error "grob_div: non-constant divisor polynomial" |
113 | _ => error "grob_div: non-constant divisor polynomial"; |
111 | _ => error "grob_div: non-constant divisor polynomial"; |
114 |
112 |
115 fun grob_pow vars l n = |
113 fun grob_pow vars l n = |
116 if n < 0 then error "grob_pow: negative power" |
114 if n < 0 then error "grob_pow: negative power" |
117 else if n = 0 then [(rat_1,map (K 0) vars)] |
115 else if n = 0 then [(@1,map (K 0) vars)] |
118 else grob_mul l (grob_pow vars l (n - 1)); |
116 else grob_mul l (grob_pow vars l (n - 1)); |
119 |
117 |
120 (* Monomial division operation. *) |
118 (* Monomial division operation. *) |
121 |
119 |
122 fun mdiv (c1,m1) (c2,m2) = |
120 fun mdiv (c1,m1) (c2,m2) = |
123 (c1 / c2, |
121 (c1 / c2, |
124 map2 (fn n1 => fn n2 => if n1 < n2 then error "mdiv" else n1 - n2) m1 m2); |
122 map2 (fn n1 => fn n2 => if n1 < n2 then error "mdiv" else n1 - n2) m1 m2); |
125 |
123 |
126 (* Lowest common multiple of two monomials. *) |
124 (* Lowest common multiple of two monomials. *) |
127 |
125 |
128 fun mlcm (_,m1) (_,m2) = (rat_1, ListPair.map Int.max (m1, m2)); |
126 fun mlcm (_,m1) (_,m2) = (@1, ListPair.map Int.max (m1, m2)); |
129 |
127 |
130 (* Reduce monomial cm by polynomial pol, returning replacement for cm. *) |
128 (* Reduce monomial cm by polynomial pol, returning replacement for cm. *) |
131 |
129 |
132 fun reduce1 cm (pol,hpol) = |
130 fun reduce1 cm (pol,hpol) = |
133 case pol of |
131 case pol of |
177 |
175 |
178 fun monic (pol,hist) = |
176 fun monic (pol,hist) = |
179 if null pol then (pol,hist) else |
177 if null pol then (pol,hist) else |
180 let val (c',m') = hd pol in |
178 let val (c',m') = hd pol in |
181 (map (fn (c,m) => (c / c',m)) pol, |
179 (map (fn (c,m) => (c / c',m)) pol, |
182 Mmul((rat_1 / c',map (K 0) m'),hist)) end; |
180 Mmul((@1 / c',map (K 0) m'),hist)) end; |
183 |
181 |
184 (* The most popular heuristic is to order critical pairs by LCM monomial. *) |
182 (* The most popular heuristic is to order critical pairs by LCM monomial. *) |
185 |
183 |
186 fun forder ((_,m1),_) ((_,m2),_) = morder_lt m1 m2; |
184 fun forder ((_,m1),_) ((_,m2),_) = morder_lt m1 m2; |
187 |
185 |
297 (* make the same calculation many times. Could put in a cache or something. *) |
295 (* make the same calculation many times. Could put in a cache or something. *) |
298 |
296 |
299 fun resolve_proof vars prf = |
297 fun resolve_proof vars prf = |
300 case prf of |
298 case prf of |
301 Start(~1) => [] |
299 Start(~1) => [] |
302 | Start m => [(m,[(rat_1,map (K 0) vars)])] |
300 | Start m => [(m,[(@1,map (K 0) vars)])] |
303 | Mmul(pol,lin) => |
301 | Mmul(pol,lin) => |
304 let val lis = resolve_proof vars lin in |
302 let val lis = resolve_proof vars lin in |
305 map (fn (n,p) => (n,grob_cmul pol p)) lis end |
303 map (fn (n,p) => (n,grob_cmul pol p)) lis end |
306 | Add(lin1,lin2) => |
304 | Add(lin1,lin2) => |
307 let val lis1 = resolve_proof vars lin1 |
305 let val lis1 = resolve_proof vars lin1 |
315 (* Run the procedure and produce Weak Nullstellensatz certificate. *) |
313 (* Run the procedure and produce Weak Nullstellensatz certificate. *) |
316 |
314 |
317 fun grobner_weak vars pols = |
315 fun grobner_weak vars pols = |
318 let val cert = resolve_proof vars (grobner_refute pols) |
316 let val cert = resolve_proof vars (grobner_refute pols) |
319 val l = |
317 val l = |
320 fold_rev (fold_rev (lcm_rat o denominator_rat o fst) o snd) cert (rat_1) in |
318 fold_rev (fold_rev (lcm_rat o denominator_rat o fst) o snd) cert @1 in |
321 (l,map (fn (i,p) => (i,map (fn (d,m) => (l * d,m)) p)) cert) end; |
319 (l,map (fn (i,p) => (i,map (fn (d,m) => (l * d,m)) p)) cert) end; |
322 |
320 |
323 (* Prove a polynomial is in ideal generated by others, using Grobner basis. *) |
321 (* Prove a polynomial is in ideal generated by others, using Grobner basis. *) |
324 |
322 |
325 fun grobner_ideal vars pols pol = |
323 fun grobner_ideal vars pols pol = |
329 |
327 |
330 (* Produce Strong Nullstellensatz certificate for a power of pol. *) |
328 (* Produce Strong Nullstellensatz certificate for a power of pol. *) |
331 |
329 |
332 fun grobner_strong vars pols pol = |
330 fun grobner_strong vars pols pol = |
333 let val vars' = @{cterm "True"}::vars |
331 let val vars' = @{cterm "True"}::vars |
334 val grob_z = [(rat_1,1::(map (K 0) vars))] |
332 val grob_z = [(@1, 1::(map (K 0) vars))] |
335 val grob_1 = [(rat_1,(map (K 0) vars'))] |
333 val grob_1 = [(@1, (map (K 0) vars'))] |
336 fun augment p= map (fn (c,m) => (c,0::m)) p |
334 fun augment p= map (fn (c,m) => (c,0::m)) p |
337 val pols' = map augment pols |
335 val pols' = map augment pols |
338 val pol' = augment pol |
336 val pol' = augment pol |
339 val allpols = (grob_sub (grob_mul grob_z pol') grob_1)::pols' |
337 val allpols = (grob_sub (grob_mul grob_z pol') grob_1)::pols' |
340 val (l,cert) = grobner_weak vars' allpols |
338 val (l,cert) = grobner_weak vars' allpols |
603 end |
601 end |
604 else tm::acc ; |
602 else tm::acc ; |
605 |
603 |
606 fun grobify_term vars tm = |
604 fun grobify_term vars tm = |
607 ((if not (member (op aconvc) vars tm) then raise CTERM ("Not a variable", [tm]) else |
605 ((if not (member (op aconvc) vars tm) then raise CTERM ("Not a variable", [tm]) else |
608 [(rat_1,map (fn i => if i aconvc tm then 1 else 0) vars)]) |
606 [(@1, map (fn i => if i aconvc tm then 1 else 0) vars)]) |
609 handle CTERM _ => |
607 handle CTERM _ => |
610 ((let val x = dest_const tm |
608 ((let val x = dest_const tm |
611 in if x = rat_0 then [] else [(x,map (K 0) vars)] |
609 in if x = @0 then [] else [(x,map (K 0) vars)] |
612 end) |
610 end) |
613 handle ERROR _ => |
611 handle ERROR _ => |
614 ((grob_neg(grobify_term vars (ring_dest_neg tm))) |
612 ((grob_neg(grobify_term vars (ring_dest_neg tm))) |
615 handle CTERM _ => |
613 handle CTERM _ => |
616 ( |
614 ( |
660 fun holify_monomial vars (c,m) = |
658 fun holify_monomial vars (c,m) = |
661 let val xps = map holify_varpow (filter (fn (_,n) => n <> 0) (vars ~~ m)) |
659 let val xps = map holify_varpow (filter (fn (_,n) => n <> 0) (vars ~~ m)) |
662 in end_itlist ring_mk_mul (mk_const c :: xps) |
660 in end_itlist ring_mk_mul (mk_const c :: xps) |
663 end |
661 end |
664 fun holify_polynomial vars p = |
662 fun holify_polynomial vars p = |
665 if null p then mk_const (rat_0) |
663 if null p then mk_const @0 |
666 else end_itlist ring_mk_add (map (holify_monomial vars) p) |
664 else end_itlist ring_mk_add (map (holify_monomial vars) p) |
667 in holify_polynomial |
665 in holify_polynomial |
668 end ; |
666 end ; |
669 |
667 |
670 fun idom_rule ctxt = simplify (put_simpset HOL_basic_ss ctxt addsimps [idom_thm]); |
668 fun idom_rule ctxt = simplify (put_simpset HOL_basic_ss ctxt addsimps [idom_thm]); |
671 fun prove_nz n = eqF_elim |
669 fun prove_nz n = eqF_elim |
672 (ring_eq_conv(mk_binop eq_tm (mk_const n) (mk_const(rat_0)))); |
670 (ring_eq_conv(mk_binop eq_tm (mk_const n) (mk_const @0))); |
673 val neq_01 = prove_nz (rat_1); |
671 val neq_01 = prove_nz @1; |
674 fun neq_rule n th = [prove_nz n, th] MRS neq_thm; |
672 fun neq_rule n th = [prove_nz n, th] MRS neq_thm; |
675 fun mk_add th1 = Thm.combination (Drule.arg_cong_rule ring_add_tm th1); |
673 fun mk_add th1 = Thm.combination (Drule.arg_cong_rule ring_add_tm th1); |
676 |
674 |
677 fun refute ctxt tm = |
675 fun refute ctxt tm = |
678 if tm aconvc false_tm then assume_Trueprop tm else |
676 if tm aconvc false_tm then assume_Trueprop tm else |
710 val th1 = |
708 val th1 = |
711 Conv.fconv_rule ((Conv.arg_conv o Conv.arg_conv) (Conv.binop_conv ring_normalize_conv)) nth |
709 Conv.fconv_rule ((Conv.arg_conv o Conv.arg_conv) (Conv.binop_conv ring_normalize_conv)) nth |
712 val th2 = funpow deg (idom_rule ctxt o HOLogic.conj_intr ctxt th1) neq_01 |
710 val th2 = funpow deg (idom_rule ctxt o HOLogic.conj_intr ctxt th1) neq_01 |
713 in (vars,l,cert,th2) |
711 in (vars,l,cert,th2) |
714 end) |
712 end) |
715 val cert_pos = map (fn (i,p) => (i,filter (fn (c,_) => c > rat_0) p)) cert |
713 val cert_pos = map (fn (i,p) => (i,filter (fn (c,_) => c > @0) p)) cert |
716 val cert_neg = map (fn (i,p) => (i,map (fn (c,m) => (minus_rat c,m)) |
714 val cert_neg = map (fn (i,p) => (i,map (fn (c,m) => (minus_rat c,m)) |
717 (filter (fn (c,_) => c < rat_0) p))) cert |
715 (filter (fn (c,_) => c < @0) p))) cert |
718 val herts_pos = map (fn (i,p) => (i,holify_polynomial vars p)) cert_pos |
716 val herts_pos = map (fn (i,p) => (i,holify_polynomial vars p)) cert_pos |
719 val herts_neg = map (fn (i,p) => (i,holify_polynomial vars p)) cert_neg |
717 val herts_neg = map (fn (i,p) => (i,holify_polynomial vars p)) cert_neg |
720 fun thm_fn pols = |
718 fun thm_fn pols = |
721 if null pols then Thm.reflexive(mk_const rat_0) else |
719 if null pols then Thm.reflexive(mk_const @0) else |
722 end_itlist mk_add |
720 end_itlist mk_add |
723 (map (fn (i,p) => Drule.arg_cong_rule (Thm.apply ring_mul_tm p) |
721 (map (fn (i,p) => Drule.arg_cong_rule (Thm.apply ring_mul_tm p) |
724 (nth eths i |> mk_meta_eq)) pols) |
722 (nth eths i |> mk_meta_eq)) pols) |
725 val th1 = thm_fn herts_pos |
723 val th1 = thm_fn herts_pos |
726 val th2 = thm_fn herts_neg |
724 val th2 = thm_fn herts_neg |