src/HOL/Tools/groebner.ML
changeset 63205 97b721666890
parent 63201 f151704c08e4
child 63211 0bec0d1d9998
equal deleted inserted replaced
63204:921a5be54132 63205:97b721666890
    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