aboutsummaryrefslogtreecommitdiffhomepage
path: root/plugins/groebner/polynom.ml
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/groebner/polynom.ml')
-rw-r--r--plugins/groebner/polynom.ml1056
1 files changed, 1056 insertions, 0 deletions
diff --git a/plugins/groebner/polynom.ml b/plugins/groebner/polynom.ml
new file mode 100644
index 000000000..5c859f755
--- /dev/null
+++ b/plugins/groebner/polynom.ml
@@ -0,0 +1,1056 @@
+(************************************************************************)
+
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*
+ Polynomes récursifs: Z[x1]...[xn].
+*)
+open Utile
+open Util
+
+(***********************************************************************
+ 1. Opérations sur les coefficients.
+*)
+
+open Big_int
+
+type coef = big_int
+let coef_of_int = big_int_of_int
+let coef_of_num = Num.big_int_of_num
+let num_of_coef = Num.num_of_big_int
+let eq_coef = eq_big_int
+let lt_coef = lt_big_int
+let le_coef = le_big_int
+let abs_coef = abs_big_int
+let plus_coef =add_big_int
+let mult_coef = mult_big_int
+let sub_coef = sub_big_int
+let opp_coef = minus_big_int
+let div_coef = div_big_int
+let mod_coef = mod_big_int
+let coef0 = coef_of_int 0
+let coef1 = coef_of_int 1
+let string_of_coef = string_of_big_int
+let int_of_coef x = int_of_big_int x
+let hash_coef x =
+ try (int_of_big_int x)
+ with _-> 1
+let puis_coef = power_big_int_positive_int
+
+(*
+type coef = Entiers.entiers
+let coef_of_int = Entiers.ent_of_int
+let coef_of_num x = (* error if x is a ratio *)
+ Entiers.ent_of_string
+ (Big_int.string_of_big_int (Num.big_int_of_num x))
+let num_of_coef x = Num.num_of_string (Entiers.string_of_ent x)
+let eq_coef = Entiers.eq_ent
+let lt_coef = Entiers.lt_ent
+let le_coef = Entiers.le_ent
+let abs_coef = Entiers.abs_ent
+let plus_coef =Entiers.add_ent
+let mult_coef = Entiers.mult_ent
+let sub_coef = Entiers.moins_ent
+let opp_coef = Entiers.opp_ent
+let div_coef = Entiers.div_ent
+let mod_coef = Entiers.mod_ent
+let coef0 = Entiers.ent0
+let coef1 = Entiers.ent1
+let string_of_coef = Entiers.string_of_ent
+let int_of_coef x = Entiers.int_of_ent x
+let hash_coef x =Entiers.hash_ent x
+let signe_coef = Entiers.signe_ent
+
+let rec puis_coef p n = match n with
+ 0 -> coef1
+ |_ -> (mult_coef p (puis_coef p (n-1)))
+*)
+
+(* a et b positifs, résultat positif *)
+let rec pgcd a b =
+ if eq_coef b coef0
+ then a
+ else if lt_coef a b then pgcd b a else pgcd b (mod_coef a b)
+
+
+(* signe du pgcd = signe(a)*signe(b) si non nuls. *)
+let pgcd2 a b =
+ if eq_coef a coef0 then b
+ else if eq_coef b coef0 then a
+ else let c = pgcd (abs_coef a) (abs_coef b) in
+ if ((lt_coef coef0 a)&&(lt_coef b coef0))
+ ||((lt_coef coef0 b)&&(lt_coef a coef0))
+ then opp_coef c else c
+
+(***********************************************************************
+ 2. Le type des polynômes, operations.
+*)
+
+type variable = int
+
+type poly =
+ Pint of coef (* polynome constant *)
+ | Prec of variable * (poly array) (* coefficients par degre croissant *)
+
+(* sauf mention du contraire, les opérations ne concernent que des
+ polynomes normalisés:
+ - les variables sont des entiers strictement positifs.
+ - les coefficients d'un polynome en x ne font intervenir que des variables < x.
+ - pas de coefficient nul en tête.
+ - pas de Prec(x,a) ou a n'a qu'un element (constant en x).
+*)
+
+(* Polynômes constant *)
+let cf x = Pint (coef_of_int x)
+let cf0 = (cf 0)
+let cf1 = (cf 1)
+
+(* la n-ième variable *)
+let x n = Prec (n,[|cf0;cf1|])
+
+(* variable max *)
+let max_var_pol p =
+ match p with
+ Pint _ -> 0
+ |Prec(x,_) -> x
+
+
+(* p n'est pas forcément normalisé *)
+let rec max_var_pol2 p =
+ match p with
+ Pint _ -> 0
+ |Prec(v,c)-> Array.fold_right (fun q m -> max (max_var_pol2 q) m) c v
+
+
+(* variable max d'une liste de polynômes *)
+let rec max_var l = Array.fold_right (fun p m -> max (max_var_pol2 p) m) l 0
+
+
+(* Egalité de deux polynômes
+ On ne peut pas utiliser = car elle ne marche pas sur les Big_int.
+*)
+let rec eqP p q =
+ match (p,q) with
+ (Pint a,Pint b) -> eq_coef a b
+ |(Prec(x,p1),Prec(y,q1)) ->
+ if x<>y then false
+ else if (Array.length p1)<>(Array.length q1) then false
+ else (try (Array.iteri (fun i a -> if not (eqP a q1.(i))
+ then failwith "raté")
+ p1;
+ true)
+ with _ -> false)
+ | (_,_) -> false
+
+(* vire les zéros de tête d'un polynôme non normalisé, dont les coefficients
+ sont supposés normalisés.
+ si constant, rend le coef constant.
+*)
+
+let rec norm p = match p with
+ Pint _ -> p
+ |Prec (x,a)->
+ let d = (Array.length a -1) in
+ let n = ref d in
+ while !n>0 && (eqP a.(!n) (Pint coef0)) do
+ n:=!n-1;
+ done;
+ if !n<0 then Pint coef0
+ else if !n=0 then a.(0)
+ else if !n=d then p
+ else (let b=Array.create (!n+1) (Pint coef0) in
+ for i=0 to !n do b.(i)<-a.(i);done;
+ Prec(x,b))
+
+
+(* degré en la variable v du polynome p, v >= max var de p *)
+let rec deg v p =
+ match p with
+ Prec(x,p1) when x=v -> Array.length p1 -1
+ |_ -> 0
+
+
+(* degré total *)
+let rec deg_total p =
+ match p with
+ Prec (x,p1) -> let d = ref 0 in
+ Array.iteri (fun i q -> d:= (max !d (i+(deg_total q)))) p1;
+ !d
+ |_ -> 0
+
+
+(* copie le polynome *)
+let rec copyP p =
+ match p with
+ Pint i -> Pint i
+ |Prec(x,q) -> Prec(x,Array.map copyP q)
+
+
+(* coefficient de degre i en v, v >= max var de p *)
+let coef v i p =
+ match p with
+ Prec (x,p1) when x=v -> if i<(Array.length p1) then p1.(i) else Pint coef0
+ |_ -> if i=0 then p else Pint coef0
+
+
+let rec plusP p q =
+ let res =
+ (match (p,q) with
+ (Pint a,Pint b) -> Pint (plus_coef a b)
+ |(Pint a, Prec (y,q1)) -> let q2=Array.map copyP q1 in
+ q2.(0)<- plusP p q1.(0);
+ Prec (y,q2)
+ |(Prec (x,p1),Pint b) -> let p2=Array.map copyP p1 in
+ p2.(0)<- plusP p1.(0) q;
+ Prec (x,p2)
+ |(Prec (x,p1),Prec (y,q1)) ->
+ if x<y then (let q2=Array.map copyP q1 in
+ q2.(0)<- plusP p q1.(0);
+ Prec (y,q2))
+ else if x>y then (let p2=Array.map copyP p1 in
+ p2.(0)<- plusP p1.(0) q;
+ Prec (x,p2))
+ else
+ (let n=max (deg x p) (deg x q) in
+ let r=Array.create (n+1) (Pint coef0) in
+ for i=0 to n do
+ r.(i)<- plusP (coef x i p) (coef x i q);
+ done;
+ Prec(x,r)))
+ in norm res
+
+
+(* contenu entier positif *)
+let rec content p =
+ match p with
+ Pint a -> abs_coef a
+ | Prec (x ,p1) ->
+ Array.fold_left pgcd coef0 (Array.map content p1)
+
+
+(* divise tous les coefficients de p par l'entier a*)
+let rec div_int p a=
+ match p with
+ Pint b -> Pint (div_coef b a)
+ | Prec(x,p1) -> Prec(x,Array.map (fun x -> div_int x a) p1)
+
+(* divise p par son contenu entier positif. *)
+let vire_contenu p =
+ let c = content p in
+ if eq_coef c coef0 then p else div_int p c
+
+
+(* liste triee des variables impliquees dans un poly *)
+let rec vars=function
+ Pint _->[]
+ | Prec (x,l)->(List.flatten ([x]::(List.map vars (Array.to_list l))))
+
+
+(* conversion d'un poly cst en entier*)
+let int_of_Pint=function
+ (Pint x)->x
+ |_->failwith "non"
+
+
+(* multiplie p par v^n, v >= max_var p *)
+let rec multx n v p =
+ match p with
+ Prec (x,p1) when x=v -> let p2= Array.create ((Array.length p1)+n) (Pint coef0) in
+ for i=0 to (Array.length p1)-1 do
+ p2.(i+n)<-p1.(i);
+ done;
+ Prec (x,p2)
+ |_ -> if p = (Pint coef0) then (Pint coef0)
+ else (let p2=Array.create (n+1) (Pint coef0) in
+ p2.(n)<-p;
+ Prec (v,p2))
+
+
+(* produit de 2 polynomes *)
+let rec multP p q =
+ match (p,q) with
+ (Pint a,Pint b) -> Pint (mult_coef a b)
+ |(Pint a, Prec (y,q1)) ->
+ if eq_coef a coef0 then Pint coef0
+ else let q2 = Array.map (fun z-> multP p z) q1 in
+ Prec (y,q2)
+
+ |(Prec (x,p1), Pint b) ->
+ if eq_coef b coef0 then Pint coef0
+ else let p2 = Array.map (fun z-> multP z q) p1 in
+ Prec (x,p2)
+ |(Prec (x,p1), Prec(y,q1)) ->
+ if x<y
+ then (let q2 = Array.map (fun z-> multP p z) q1 in
+ Prec (y,q2))
+ else if x>y
+ then (let p2 = Array.map (fun z-> multP z q) p1 in
+ Prec (x,p2))
+ else Array.fold_left plusP (Pint coef0)
+ (Array.mapi (fun i z-> (multx i x (multP z q))) p1)
+
+
+
+(* derive p par rapport a la variable v, v >= max_var p *)
+let rec deriv v p =
+ match p with
+ Pint a -> Pint coef0
+ |Prec(x,p1) when x=v ->
+ let d = Array.length p1 -1 in
+ if d=1 then p1.(1)
+ else
+ (let p2 = Array.create d (Pint coef0) in
+ for i=0 to d-1 do
+ p2.(i)<- multP (Pint (coef_of_int (i+1))) p1.(i+1);
+ done;
+ Prec (x,p2))
+ |Prec(x,p1)-> Pint coef0
+
+
+(* opposé de p *)
+let rec oppP p =
+ match p with
+ Pint a -> Pint (opp_coef a)
+ |Prec(x,p1) -> Prec(x,Array.map oppP p1)
+
+
+(* différence de deux polynômes. *)
+let moinsP p q=plusP p (oppP q)
+
+let rec puisP p n = match n with
+ 0 -> cf1
+ |_ -> (multP p (puisP p (n-1)))
+
+
+(* notations infixes...*)
+(*let (++) a b = plusP a b
+*)
+let (@@) a b = multP a b
+
+let (--) a b = moinsP a b
+
+let (^^) a b = puisP a b
+
+
+(* coefficient dominant de p, v>= max_var p *)
+
+let coefDom v p= coef v (deg v p) p
+
+
+let coefConst v p = coef v 0 p
+
+(* queue d'un polynôme *)
+let remP v p =
+ moinsP p (multP (coefDom v p) (puisP (x v) (deg v p)))
+
+
+(* premier coef entier de p *)
+let rec coef_int_tete p =
+ let v = max_var_pol p in
+ if v>0
+ then coef_int_tete (coefDom v p)
+ else (match p with | Pint a -> a |_ -> assert false)
+
+
+(* divise par le contenu, et rend positif le premier coefficient entier *)
+let normc p =
+ let p = vire_contenu p in
+ let a = coef_int_tete p in
+ if le_coef coef0 a then p else oppP p
+
+
+(* teste si un polynome est constant *)
+let is_constantP p = match p with
+ Pint _ -> true
+ |Prec (_,_) -> false
+
+
+(* teste si un poly est identiquement nul *)
+let is_zero p =
+ match p with Pint n -> if eq_coef n coef0 then true else false |_-> false
+
+(* crée rapidement v^n *)
+let monome v n =
+ match n with
+ 0->Pint coef1;
+ |_->let tmp = Array.create (n+1) (Pint coef0) in
+ tmp.(n)<-(Pint coef1);
+ Prec (v, tmp)
+
+
+(*coef constant d'un polynome normalise*)
+let rec coef_constant p =
+ match p with
+ Pint a->a
+ |Prec(_,q)->coef_constant q.(0)
+
+
+(***********************************************************************
+ 3. Affichage des polynômes.
+*)
+
+(* si univ=false, on utilise x,y,z,a,b,c,d... comme noms de variables,
+ sinon, x1,x2,...
+*)
+let univ=ref true
+
+(* joli jusqu'a trois variables -- sinon changer le 'w' *)
+let string_of_var x=
+ if !univ then
+ "u"^(string_of_int x)
+ else
+ if x<=3 then String.make 1 (Char.chr(x+(Char.code 'w')))
+ else String.make 1 (Char.chr(x-4+(Char.code 'a')))
+
+let nsP = ref 0
+
+let rec string_of_Pcut p =
+ if (!nsP)<=0
+ then "..."
+ else
+ match p with
+ |Pint a-> nsP:=(!nsP)-1;
+ if le_coef coef0 a
+ then string_of_coef a
+ else "("^(string_of_coef a)^")"
+ |Prec (x,t)->
+ let v=string_of_var x
+ and s=ref ""
+ and sp=ref "" in
+ let st0 = string_of_Pcut t.(0) in
+ if st0<>"0"
+ then s:=st0;
+ let fin = ref false in
+ for i=(Array.length t)-1 downto 1 do
+ if (!nsP)<0
+ then (sp:="...";
+ if not (!fin) then s:=(!s)^"+"^(!sp);
+ fin:=true)
+ else (
+ let si=string_of_Pcut t.(i) in
+ sp:="";
+ if i=1
+ then (
+ if si<>"0"
+ then (nsP:=(!nsP)-1;
+ if si="1"
+ then sp:=v
+ else
+ (if (String.contains si '+')
+ then sp:="("^si^")*"^v
+ else sp:=si^"*"^v)))
+ else (
+ if si<>"0"
+ then (nsP:=(!nsP)-1;
+ if si="1"
+ then sp:=v^"^"^(string_of_int i)
+ else (if (String.contains si '+')
+ then sp:="("^si^")*"^v^"^"^(string_of_int i)
+ else sp:=si^"*"^v^"^"^(string_of_int i))));
+ if !sp<>"" && not (!fin)
+ then (nsP:=(!nsP)-1;
+ if !s=""
+ then s:=!sp
+ else s:=(!s)^"+"^(!sp)));
+ done;
+ if !s="" then (nsP:=(!nsP)-1;
+ (s:="0"));
+ !s
+
+let string_of_P p =
+ nsP:=20;
+ string_of_Pcut p
+
+let printP p = Format.printf "@[%s@]" (string_of_P p)
+
+
+let print_tpoly lp =
+ let s = ref "\n{ " in
+ Array.iter (fun p -> s:=(!s)^(string_of_P p)^"\n") lp;
+ prt0 ((!s)^"}")
+
+
+let print_lpoly lp = print_tpoly (Array.of_list lp)
+
+(* #install_printer printP *)
+
+(***********************************************************************
+ 4. Division exacte de polynômes.
+*)
+
+(* rend (s,r) tel que p = s*q+r *)
+let rec quo_rem_pol p q x =
+ if x=0
+ then (match (p,q) with
+ |(Pint a, Pint b) ->
+ if eq_coef (mod_coef a b) coef0
+ then (Pint (div_coef a b), cf 0)
+ else failwith "div_pol1"
+ |_ -> assert false)
+ else
+ let m = deg x q in
+ let b = coefDom x q in
+ let q1 = remP x q in (* q = b*x^m+q1 *)
+ let r = ref p in
+ let s = ref cf0 in
+ let continue =ref true in
+ while (!continue) && (not (eqP !r cf0)) do
+ let n = deg x !r in
+ if n<m
+ then continue:=false
+ else (
+ let a = coefDom x !r in
+ let p1 = remP x !r in (* r = a*x^n+p1 *)
+ let c = div_pol a b (x-1) in (* a = c*b *)
+ let s1 = c @@ ((monome x (n-m))) in
+ s:= plusP (!s) s1;
+ r:= p1 -- (s1 @@ q1);
+ )
+ done;
+ (!s,!r)
+
+(* echoue si q ne divise pas p, rend le quotient sinon *)
+and div_pol p q x =
+ let (s,r) = quo_rem_pol p q x in
+ if eqP r cf0
+ then s
+ else failwith ("div_pol:\n"
+ ^"p:"^(string_of_P p)^"\n"
+ ^"q:"^(string_of_P q)^"\n"
+ ^"r:"^(string_of_P r)^"\n"
+ ^"x:"^(string_of_int x)^"\n"
+ )
+
+
+(* test de division exacte de p par q mais constantes rationnels
+ à vérifier *)
+let divP p q=
+ let x = max (max_var_pol p) (max_var_pol q) in
+ div_pol p q x
+
+(* test de division exacte de p par q mais constantes rationnels
+ à vérifier *)
+let div_pol_rat p q=
+ let x = max (max_var_pol p) (max_var_pol q) in
+ try (let s = div_pol (multP p (puisP (Pint(coef_int_tete q))
+ (1+(deg x p) - (deg x q))))
+ q x in
+ (*degueulasse, mais c 'est pour enlever un warning *)
+ if s==s then true else true)
+ with _ -> false
+
+
+
+
+(***********************************************************************
+ 5. Pseudo-division et pgcd par les sous-résultants.
+*)
+
+(* pseudo division :
+ q = c*x^m+q1
+ rend (r,c,d,s) tels que c^d*p = s*q + r.
+*)
+
+let pseudo_div p q x =
+ match q with
+ Pint _ -> (cf0, q,1, p)
+ | Prec (v,q1) when x<>v -> (cf0, q,1, p)
+ | Prec (v,q1) ->
+ (
+ (* pr "pseudo_division: c^d*p = s*q + r";*)
+ let delta = ref 0 in
+ let r = ref p in
+ let c = coefDom x q in
+ let q1 = remP x q in
+ let d' = deg x q in
+ let s = ref cf0 in
+ while (deg x !r)>=(deg x q) do
+ let d = deg x !r in
+ let a = coefDom x !r in
+ let r1=remP x !r in
+ let u = a @@ ((monome x (d-d'))) in
+ r:=(c @@ r1) -- (u @@ q1);
+ s:=plusP (c @@ (!s)) u;
+ delta := (!delta) + 1;
+ done;
+ (*
+ pr ("deg d: "^(string_of_int (!delta))^", deg c: "^(string_of_int (deg_total c)));
+ pr ("deg r:"^(string_of_int (deg_total !r)));
+ *)
+ (!r,c,!delta, !s)
+ )
+
+
+(* pgcd de polynômes par les sous-résultants *)
+
+
+let rec pgcdP p q =
+ let x = max (max_var_pol p) (max_var_pol q) in
+ pgcd_pol p q x
+
+and pgcd_pol p q x =
+ pgcd_pol_rec p q x
+
+and content_pol p x =
+ match p with
+ Prec(v,p1) when v=x ->
+ Array.fold_left (fun a b -> pgcd_pol_rec a b (x-1)) cf0 p1
+ | _ -> p
+
+and pgcd_coef_pol c p x =
+ match p with
+ Prec(v,p1) when x=v ->
+ Array.fold_left (fun a b -> pgcd_pol_rec a b (x-1)) c p1
+ |_ -> pgcd_pol_rec c p (x-1)
+
+
+and pgcd_pol_rec p q x =
+ match (p,q) with
+ (Pint a,Pint b) -> Pint (pgcd (abs_coef a) (abs_coef b))
+ |_ ->
+ if eqP p cf0
+ then q
+ else if eqP q cf0
+ then p
+ else if (deg x q) = 0
+ then pgcd_coef_pol q p x
+ else if (deg x p) = 0
+ then pgcd_coef_pol p q x
+ else (
+ let a = content_pol p x in
+ let b = content_pol q x in
+ let c = pgcd_pol_rec a b (x-1) in
+ pr (string_of_int x);
+ let p1 = div_pol p c x in
+ let q1 = div_pol q c x in
+ let r = gcd_sub_res p1 q1 x in
+ let cr = content_pol r x in
+ let res = c @@ (div_pol r cr x) in
+ res
+ )
+
+(* version avec memo*)
+(*
+and htblpgcd = Hashtbl.create 1000
+
+and pgcd_pol_rec p q x =
+ try
+ (let c = Hashtbl.find htblpgcd (p,q,x) in
+ (*info "*";*)
+ c)
+ with _ ->
+ (let c =
+ (match (p,q) with
+ (Pint a,Pint b) -> Pint (pgcd (abs_coef a) (abs_coef b))
+ |_ ->
+ if eqP p cf0
+ then q
+ else if eqP q cf0
+ then p
+ else if (deg x q) = 0
+ then pgcd_coef_pol q p x
+ else if (deg x p) = 0
+ then pgcd_coef_pol p q x
+ else (
+ let a = content_pol p x in
+ let b = content_pol q x in
+ let c = pgcd_pol_rec a b (x-1) in
+ pr (string_of_int x);
+ let p1 = div_pol p c x in
+ let q1 = div_pol q c x in
+ let r = gcd_sub_res p1 q1 x in
+ let cr = content_pol r x in
+ let res = c @@ (div_pol r cr x) in
+ res
+ )
+ )
+ in
+ (*info "-";*)
+ Hashtbl.add htblpgcd (p,q,x) c;
+ c)
+*)
+(* Sous-résultants:
+
+ ai*Ai = Qi*Ai+1 + bi*Ai+2
+
+ deg Ai+2 < deg Ai+1
+
+ Ai = ci*X^ni + ...
+ di = ni - ni+1
+
+ ai = (- ci+1)^(di + 1)
+ b1 = 1
+ bi = ci*si^di si i>1
+
+ s1 = 1
+ si+1 = ((ci+1)^di*si)/si^di
+
+*)
+and gcd_sub_res p q x =
+ if eqP q cf0
+ then p
+ else
+ let d = deg x p in
+ let d' = deg x q in
+ if d<d'
+ then gcd_sub_res q p x
+ else
+ let delta = d-d' in
+ let c' = coefDom x q in
+ let r = snd (quo_rem_pol (((oppP c')^^(delta+1))@@p) (oppP q) x) in
+ gcd_sub_res_rec q r (c'^^delta) c' d' x
+
+and gcd_sub_res_rec p q s c d x =
+ if eqP q cf0
+ then p
+ else (
+ let d' = deg x q in
+ let c' = coefDom x q in
+ let delta = d-d' in
+ let r = snd (quo_rem_pol (((oppP c')^^(delta+1))@@p) (oppP q) x) in
+ let s'= lazard_power c' s delta x in
+ gcd_sub_res_rec q (div_pol r (c @@ (s^^delta)) x) s' c' d' x
+ )
+
+and lazard_power c s d x =
+ let res = ref c in
+ for i=1 to d-1 do
+ res:= div_pol ((!res)@@c) s x;
+ done;
+ !res
+
+
+
+(***********************************************************************
+ 6. Décomposition sans carré, factorisation.
+*)
+
+(*
+ p = f1 f2^2 ... fn^r
+ p/\p'= f2 f3^2...fn^(r-1)
+ sans_carré(p)= p/p/\p '= f1 f2 ... fn
+*)
+
+let sans_carre p x =
+ if (deg x p) <= 1 then p
+ else
+ let p' = deriv x p in
+ div_pol p (pgcd_pol p p' x) x
+
+
+(* liste [f1;...;fn] *)
+let facteurs p x =
+ let rec facteurs_rec p q =
+ if (deg x p)=0 then []
+ else
+ let p2 = div_pol p q x in
+ let q2 = sans_carre p2 x in
+ (div_pol q q2 x)::(facteurs_rec p2 q2)
+ in facteurs_rec p (sans_carre p x)
+
+
+(* liste [f1;f3;...] *)
+let facteurs_impairs p x =
+ let lf = Array.of_list (facteurs p x) in
+ let r = ref [] in
+ Array.iteri (fun i f ->
+ if ((i+1) mod 2)=1
+ then r:=(!r)@[f])
+ lf;
+ !r
+
+
+(* décomposition sans carrés en toutes les variables *)
+
+
+let hcontentP = Hashtbl.create 51
+
+let prcontentP () =
+ Hashtbl.iter (fun s c ->
+ prn (s^" -> "^(string_of_P c)))
+ hcontentP
+
+
+let contentP =
+ memos "c" hcontentP (fun (p,x) -> ((string_of_P p)^":"^(string_of_int x)))
+ (fun (p,x) -> content_pol p x)
+
+
+(* Tables de hash et polynômes, mémo *)
+
+(* dans le mli on écrit:
+ module Hashpol:Hashtbl.S with type t = poly
+*)
+
+(* fonction de hachage des polynômes *)
+let hashP p =
+ let rec hP p =
+ match p with
+ Pint a -> (hash_coef a)
+ |Prec (v,p) ->
+ (Array.fold_right (fun q h -> h+(hP q)) p 0)
+ in (* Hashtbl.hash *) (hP p)
+
+
+module Hashpol = Hashtbl.Make(
+ struct
+ type t = poly
+ let equal = eqP
+ let hash = hashP
+ end)
+
+
+let memoP s memoire fonction x =
+ try (let v = Hashpol.find memoire x in pr s;v)
+ with _ -> (pr "#";
+ let v = fonction x in
+ Hashpol.add memoire x v;
+ v)
+
+
+let hfactorise = Hashpol.create 51
+
+let prfactorise () =
+ Hashpol.iter (fun p c ->
+ prn ((string_of_P p)^" -> ");
+ print_lpoly (List.flatten c))
+ hfactorise
+
+let factorise =
+ memoP "f" hfactorise
+ (fun p ->
+ let rec fact p x =
+ if x=0
+ then []
+ else
+ let c = contentP (p,x) in
+ let q = div_pol p c x in
+ (facteurs q x)::(fact c (x-1))
+ in fact p (max_var_pol p))
+
+
+(* liste des facteurs sans carré non constants,
+ avec coef entier de tête positif *)
+let facteurs2 p =
+ List.map normc
+ (List.filter (fun q -> deg_total q >0)
+ (List.flatten (factorise (normc p))))
+
+
+(* produit des facteurs non constants d'une décomposition sans carré *)
+let pol_de_factorisation lf =
+ let p = ref cf1 in
+ List.iter (fun lq ->
+ Array.iteri (fun i q -> if (deg_total q)>0 then p:=(!p)@@(q^^(i+1)))
+ (Array.of_list lq))
+ lf;
+ !p
+
+
+let set_of_array_facteurs tf =
+ let h = Hashpol.create 51 in
+ Array.iter (fun lf ->
+ List.iter (fun p -> if not (Hashpol.mem h p)
+ then Hashpol.add h p true)
+ lf)
+ tf;
+ let res = ref [] in
+ Hashpol.iter (fun p _ -> res:=p::(!res)) h;
+ !res
+
+
+(* Factorise un tableau de polynômes f, et rend:
+ - un tableau p de facteurs (degré>0, contenu entier 1,
+ coefficient de tête >0) obtenu par décomposition sans carrés
+ puis par division mutuelle
+ - un tableau l de couples (constante, listes d'indices l)
+ tels que f.(i) = l.(i)_1*Produit(p.(j), j dans l.(i)_2)
+*)
+
+(* on donne le tableau des facteurs de chaque poly de f *)
+let factorise_tableauP2 f l1 =
+ let x = max_var f in
+ (* liste des facteurs sans carré des polynômes de f *)
+ pr"<";
+ let l1 = set_of_array_facteurs l1 in
+ (* on les divise entre eux pour éventuellement trouver
+ de nouveaux facteurs *)
+ pr "~";
+ let l1 = Sort.list (fun p q -> (deg_total p)<(deg_total q)) l1 in
+ let l1 = Array.of_list (facteurs_liste (fun a b -> div_pol a b x)
+ (fun p -> (deg_total p)<1)
+ l1) in
+ (* puis on décompose les polynômes de f avec ces facteurs *)
+ pr "-";
+ let res = factorise_tableau (fun a b -> div_pol a b x)
+ (fun p -> eqP p cf0)
+ cf0
+ f l1 in
+ pr ">";
+ res
+
+let factorise_tableauP f =
+ factorise_tableauP2 f (Array.map facteurs2 f)
+
+
+(***********************************************************************
+ 7. Pseudo-division avec reste de même signe,
+ en utilisant des polynômes non nuls pour diviser le reste.
+*)
+
+(* polynôme pair et coefficients positifs *)
+let rec is_positif p =
+
+ let res =
+ match p with
+ Pint a -> le_coef coef0 a
+ |Prec(x,p1) ->
+ (array_for_all is_positif p1)
+ && (try (Array.iteri (fun i c -> if (i mod 2)<>0 && not (eqP c cf0)
+ then failwith "pas pair")
+ p1;
+ true)
+ with _ -> false)
+ in
+ res
+
+
+
+let is_negatif p = is_positif (oppP p)
+
+
+(* rend r tel que deg r < deg q et r a le signe de p en les racines de q.
+ le coefficient dominant de q est non nul
+ quand les polynômes de coef_non_nuls le sont.
+ (rs,cs,ds,ss,crs,lpos,lpol)= pseudo_euclide coef_non_nuls vect.(s-1) res.(s-1) v
+*)
+let pseudo_euclide coef_non_nuls p q x =
+ let (r,c,d,s) = pseudo_div p q x in
+ (*
+ c^d * p = s*q + r, c = coef dominant de q
+ *)
+ (* vérification de la pseudo-division:
+ let verif = ((c^^d)@@p)--(plusP (s@@q) r) in
+ if not (eqP verif cf0)
+ then (prn ("p:"^(string_of_P p));
+ prn ("q:"^(string_of_P q));
+ prn ("c:"^(string_of_P c));
+ prn ("r:"^(string_of_P r));
+ prn ("d:"^(string_of_int d));
+ failwith "erreur dans la pseudo-division");
+ *)
+
+ (* pour autoriser des c pas positifs, il faut modifier algo14 et preuve3*)
+ let r = if d mod 2 = 1 then c@@r else r in
+ let s = if d mod 2 = 1 then c@@s else s in
+ let d = if d mod 2 = 1 then d+1 else d in
+
+ (* on encore c^d * p = s*q + r, mais d pair *)
+ if eqP r cf0
+ then ((*pr "reste nul"; *) (r,c,d,s,cf1,[],[]))
+ else (
+ let r1 = vire_contenu r in
+ let cr = div_pol r r1 x in
+ let r = ref r1 in
+ (* r a maintenant le même signe que p en les racines de q.*)
+ (* on tente de diviser r par les polynômes de coef_non_nuls *)
+ let lf = ref [] in (* liste de (facteur, puissance) *)
+ List.iter (fun f ->
+ if (deg_total f)>0 && (max_var_pol f) < x
+ then (
+ let k = ref 0 in
+ (try (while true do
+ let rd = div_pol !r f x in
+ (* verification de la division
+ if not (eqP cf0 ((!r)--(f@@rd)))
+ then failwith "erreur dans la division";
+ *)
+ k:=(!k)+1;
+ r:=rd;
+ (*pr "+";*)
+ done)
+ with _ -> ());
+ lf:=(f,!k)::(!lf)))
+ coef_non_nuls;
+ (* il faut éventuellement remultiplier pour garder le signe de r *)
+ let lpos = ref [] in
+ let lpol = ref [] in
+ List.iter (fun (f,k) ->
+ if k>0
+ then (
+ if (is_positif f)
+ (* f est positif, tout va bien *)
+ then lpos:=(f,k)::(!lpos)
+ else if (is_negatif f)
+ (* f est négatif *)
+ then (if k mod 2 = 1
+ (* k est impair *)
+ then (lpos:=(oppP f,k)::(!lpos);
+ r:=oppP (!r))
+ else lpos:=(f,k)::(!lpos))
+ (* on ne connaît pas le signe de f *)
+ else if k mod 2 = 0
+ (* k est pair, tout va bien *)
+ then lpol:=(f,k)::(!lpol)
+ (* k est impair *)
+ else (lpol:=(f,k-1)::(!lpol);
+ r:=multP (!r) f)))
+ !lf;
+ (*
+ pr ((* "------reste de même signe: "
+ ^(string_of_P c)
+ ^" variable: "^(string_of_int x)
+ ^" c:"^(string_of_int (deg_total c))
+ ^" d:"^(string_of_int d)
+ ^" deg(r)-deg(r0):"
+ ^*)(string_of_int ((deg_total !r)-(deg_total r0))));
+ *)
+ (* lpos = liste de (f,k) ou f est non nul positif, et f^k divise r0
+ lpol = liste de (f,k) ou f non nul, k est pair et f^k divise r0
+ on c^d * p = s*q + r0
+ avec d pair
+ r0 = cr * r * PI_lpos f^k * PI_lpol g^k
+ cr non nul positif
+ *)
+ (!r,c,d,s,cr,!lpos,!lpol))
+
+
+
+(* teste si la non-nullité des polynômes de lp entraîne celle de p:
+ chacun des facteurs de la décomposition sans carrés de p
+ divise un des polynômes de lp (dans Q[x1...xn]) *)
+
+let implique_non_nul lp p =
+ if eqP p cf0 then false
+ else(
+ pr "[";
+ let lf = facteurs2 p in
+ let r =(
+ try (List.iter (fun f ->
+ if (try (List.iter (fun q ->
+ if div_pol_rat q f
+ then failwith "divise")
+ lp;
+ true)
+ with _ -> false)
+ then failwith "raté")
+ lf;
+ true)
+ with _ -> false)
+ in pr "]";r)
+
+
+let ajoute_non_nul p lp =
+ if (deg_total p) >0
+ then(
+ let p = normc p in
+ let lf = facteurs2 p in
+ let r = set_of_list_eq eqP (lp@lf@[p]) in
+ r)
+ else lp
+