1 /* -*- mode:C++ ; compile-command: "g++-3.4 -I.. -I../include -g -c gausspol.cc -D_I386_ -DHAVE_CONFIG_H -DIN_GIAC" -*- */
2 #include "giacPCH.h"
3 /*
4  *  This file implements several functions that work on univariate and
5  *  multivariate polynomials and rational functions.
6  *  These functions include polynomial quotient and remainder, GCD and LCM
7  *  computation, factorization and rational function normalization. */
8 
9 /*
10  *  Copyright (C) 2000,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 3 of the License, or
15  *  (at your option) any later version.
16  *
17  *  This program is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with this program. If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 using namespace std;
27 #include "gausspol.h"
28 #include "modpoly.h"
29 #include "modfactor.h"
30 #include "solve.h" // for has_num_coeff
31 #include "alg_ext.h"
32 #include "sym2poly.h"
33 #include "prog.h"
34 #include "plot.h"
35 #include "modpoly.h"
36 #include "threaded.h"
37 #include "usual.h"
38 #include "ezgcd.h"
39 #include "giacintl.h"
40 #include <math.h>
41 #include <stdexcept>
42 
43 #ifdef USE_GMP_REPLACEMENTS
44 #undef HAVE_GMPXX_H
45 #undef HAVE_LIBMPFR
46 #endif
47 
48 #ifdef HAVE_GMPXX_H
49 #define myint mpz_class
50 #else
51 #define myint my_mpz
52 #endif
53 
54 // #undef HAVE_LIBNTL
55 
56 #ifdef USTL
57 namespace ustl {
operator >(const giac::index_t & a,const giac::index_t & b)58   inline bool operator > (const giac::index_t & a,const giac::index_t & b){
59     if (a.size()!=b.size())
60       return a.size()>b.size();
61     return !giac::all_inf_equal(a,b);
62   }
operator <(const giac::index_t & a,const giac::index_t & b)63   inline bool operator < (const giac::index_t & a,const giac::index_t & b){
64     if (a.size()!=b.size())
65       return a.size()<b.size();
66     return !giac::all_sup_equal(a,b);
67   }
68 }
69 #endif
70 
71 #ifndef NO_NAMESPACE_GIAC
72 namespace giac {
73 #endif // ndef NO_NAMESPACE_GIAC
74 
75   const int primes[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541};
76 
77   // trivial division factorization algorithm
trivial_n_factor(gen & n)78   vector<nfactor> trivial_n_factor(gen &n){
79     vector<nfactor> v;
80     if (is_zero(n))
81       return v;
82     for (int i=0;i<sizeof(primes)/sizeof(int);i++){
83       gen p(primes[i]);
84       if (is_zero(n % p) ){
85 	int j=1;
86 	n=iquo(n,p);
87 	while (is_zero(n % p)){
88 	  n=iquo(n,p);
89 	  j++;
90 	}
91 	v.push_back(nfactor(p,j));
92       }
93       if (is_strictly_greater(p*p,n,context0))
94 	break;
95     }
96     if (n!=gen(1))
97       v.push_back(nfactor(n,1));
98     return v;
99   }
100 
101 #if 0
102   struct is_strictly_smaller_t {
103     is_strictly_smaller_t(){}
104     bool operator ()(const gen & a,const gen & b){
105       return is_strictly_greater(b,a,context0); // return (a<b)
106     }
107   };
108 
109   vecteur divisor(const gen & n){
110     gen ntemp;
111     if (!is_positive(n,context0)) // ok
112       ntemp=-n;
113     else
114       ntemp=n;
115     vector<nfactor> nv(trivial_n_factor(ntemp));
116     int k=nv.size();
117     vecteur v;
118     v.push_back(gen(1));
119     for (int j=0;j<k;j++){
120       gen current(1);
121       int mult=nv[j].mult;
122       gen multiplie(nv[j].fact);
123       v.reserve(v.size()*(mult+1));
124       vecteur::const_iterator itbeg=v.begin();
125       vecteur::const_iterator itend=v.end();
126       for (int i=0;i<mult;i++){
127 	current=current*multiplie;
128 	vecteur::const_iterator it=itbeg;
129 	// COUT << "for " << *it << '\n';
130 	for (;it!=itend;++it){
131 	  gen temp((*it)*current);
132 	  // COUT << *it << " " << current << " " << temp << '\n';
133 	  v.push_back( temp );
134 	}
135       }
136     }
137     sort(v.begin(),v.end(),is_strictly_smaller_t());
138     return v;
139   }
140 #endif
141 
cyclotomic(int n)142   vecteur cyclotomic(int n){
143     // Algorithm base sur les relations suivantes
144     // soit p premier, si p ne divise pas n alors
145     // cyclo_{n}(X^p)=cyclo_{np}(X)*cyclo_{n}(X)
146     // si p divise n alors
147     // cyclo_{n}(X^p)=cyclo_{np}(X)
148     //
149     // poser f(x)=x-1
150     // parcourir la liste des facteurs premiers de n ordonnee par ordre
151     // croissant et pour chaque facteur premier p effecter f(x)=f(x^p)/f(x).
152     // Le polynome cyclotomique P_n est alors f(x^[n/pi]) ou pi est le produit
153     // des facteurs premiers.
154     // Par exemple
155     // n=6 donne la liste { 2 3 }
156     // p=2: f(x)=(x^2-1)/(x-1)=x+1
157     // p=3: f(x)=(x^3+1)/(x+1)=x^2-x+1
158     // n/pi=1 c'est fini
159     //
160     // n=100 donne { 2 5 }
161     // p=2: f(x)=x+1
162     // p=5: f(x)=(x^5+1)/(x+1)=x^4-x^3+x^2-x+1
163     // n/pi=10 donc f(x)=x^40-x^30+x^20-x^10+1
164     gen ncopy(n);
165     vector<nfactor> v(trivial_n_factor(ncopy));
166     vecteur res;
167     res.push_back(1);
168     res.push_back(-1); // res=x-1
169     int pi=1;
170     vector<nfactor>::const_iterator it=v.begin(),itend=v.end();
171     for (;it!=itend;++it){
172       if (it->fact.type!=_INT_)
173 	return vecteur(1,gensizeerr(gettext("gausspol.cc/cyclotomic")));
174       int p=it->fact.val;
175       pi *= p;
176       vecteur res_x_to_xp(x_to_xp(res,p));
177       res=res_x_to_xp/res;
178     }
179     return x_to_xp(res,n/pi);
180   }
181 
182   //**********************************
183   // functions relative to polynomials
184   //**********************************
gen2polynome(const gen & e,int dim)185   polynome gen2polynome(const gen & e,int dim){
186     if (e.type==_POLY)
187       return *e._POLYptr;
188     return polynome(e,dim);
189   }
190 
191   // instantiation of dbgprint for poly
dbg(const polynome & p)192   void dbg(const polynome & p){
193     p.dbgprint();
194   }
195 
is_one(const polynome & p)196   bool is_one(const polynome & p){
197     return Tis_one<gen>(p);
198   }
199 
firstcoeff(const polynome & p)200   polynome firstcoeff(const polynome & p){
201     return Tfirstcoeff<gen>(p);
202   }
203 
Add_gen(std::vector<monomial<gen>>::const_iterator & a,std::vector<monomial<gen>>::const_iterator & a_end,std::vector<monomial<gen>>::const_iterator & b,std::vector<monomial<gen>>::const_iterator & b_end,std::vector<monomial<gen>> & new_coord,bool (* is_strictly_greater)(const index_m &,const index_m &))204   void Add_gen ( std::vector< monomial<gen> >::const_iterator & a,
205 		 std::vector< monomial<gen> >::const_iterator & a_end,
206 		 std::vector< monomial<gen> >::const_iterator & b,
207 		 std::vector< monomial<gen> >::const_iterator & b_end,
208 		 std::vector< monomial<gen> > & new_coord,
209 		 bool (* is_strictly_greater)( const index_m &, const index_m &)) {
210     if ( (a!=a_end && new_coord.begin()==a) || (b!=b_end && new_coord.begin()==b)){
211       std::vector< monomial<gen> > tmp;
212       Add_gen(a,a_end,b,b_end,tmp,is_strictly_greater);
213       std::swap(new_coord,tmp);
214       return;
215     }
216     new_coord.clear();
217     new_coord.reserve( (a_end - a) + (b_end - b));
218     gen sum;
219     for (;;) {
220       if (a == a_end) {
221 	while (b != b_end) {
222 	  new_coord.push_back(*b);
223 	  ++b;
224 	}
225 	break;
226       }
227       const index_m & pow_a = a->index;
228       // If b is empty, fill up with elements from a and stop
229       if (b == b_end) {
230 	while (a != a_end) {
231 	  new_coord.push_back(*a);
232 	  ++a;
233 	}
234 	break;
235       }
236       const index_m & pow_b = b->index;
237       // a and b are non-empty, compare powers
238       if (pow_a!=pow_b){
239 	if (is_strictly_greater(pow_a, pow_b)) {
240 	  // a has lesser power, get coefficient from a
241 	  new_coord.push_back(*a);
242 	  ++a;
243 	}
244 	else  {
245 	  // b has lesser power, get coefficient from b
246 	  new_coord.push_back(*b);
247 	  ++b;
248 	}
249       }
250       else {
251 	sum = (*a).value + (*b).value;
252 	if (!is_zero(sum))
253 	  new_coord.push_back(monomial<gen>(sum,pow_a));
254 	++a;
255 	++b;
256       }
257     }
258   }
259 
operator +(const polynome & th,const polynome & other)260   polynome operator + (const polynome & th,const polynome & other) {
261 #ifdef TIMEOUT
262     control_c();
263 #endif
264     if (ctrl_c || interrupted) {
265       interrupted = true; ctrl_c=false;
266       return monomial<gen>(gensizeerr(gettext("Stopped by user interruption.")),th.dim);
267     }
268     // Tensor addition
269     vector< monomial<gen> >::const_iterator a=th.coord.begin();
270     vector< monomial<gen> >::const_iterator a_end=th.coord.end();
271     if (a == a_end) {
272       return other;
273     }
274     vector< monomial<gen> >::const_iterator b=other.coord.begin();
275     vector< monomial<gen> >::const_iterator b_end=other.coord.end();
276     if (b==b_end){
277       return th;
278     }
279     polynome res(th.dim,th);
280     Add_gen(a,a_end,b,b_end,res.coord,th.is_strictly_greater);
281     return res;
282   }
283 
Sub_gen(std::vector<monomial<gen>>::const_iterator & a,std::vector<monomial<gen>>::const_iterator & a_end,std::vector<monomial<gen>>::const_iterator & b,std::vector<monomial<gen>>::const_iterator & b_end,std::vector<monomial<gen>> & new_coord,bool (* is_strictly_greater)(const index_m &,const index_m &))284   void Sub_gen ( std::vector< monomial<gen> >::const_iterator & a,
285 		 std::vector< monomial<gen> >::const_iterator & a_end,
286 		 std::vector< monomial<gen> >::const_iterator & b,
287 		 std::vector< monomial<gen> >::const_iterator & b_end,
288 		 std::vector< monomial<gen> > & new_coord,
289 		 bool (* is_strictly_greater)( const index_m &, const index_m &)) {
290     if ( (a!=a_end && new_coord.begin()==a) || (b!=b_end && new_coord.begin()==b)){
291       std::vector< monomial<gen> > tmp;
292       Sub_gen(a,a_end,b,b_end,tmp,is_strictly_greater);
293       std::swap(new_coord,tmp);
294       return;
295     }
296     new_coord.clear();
297     new_coord.reserve( (a_end - a) + (b_end - b));
298     gen diff;
299     for (;;) {
300       if (a == a_end) {
301 	while (b != b_end) {
302 	  new_coord.push_back(-(*b));
303 	  ++b;
304 	}
305 	break;
306       }
307       const index_m & pow_a = a->index;
308       // If b is empty, fill up with elements from a and stop
309       if (b == b_end) {
310 	while (a != a_end) {
311 	  new_coord.push_back(*a);
312 	  ++a;
313 	}
314 	break;
315       }
316       const index_m & pow_b = b->index;
317       // a and b are non-empty, compare powers
318       if (pow_a!=pow_b){
319 	if (is_strictly_greater(pow_a, pow_b)) {
320 	  // a has lesser power, get coefficient from a
321 	  new_coord.push_back(*a);
322 	  ++a;
323 	}
324 	else  {
325 	  // b has lesser power, get coefficient from b
326 	  new_coord.push_back(-(*b));
327 	  ++b;
328 	}
329       }
330       else {
331 	diff = (*a).value - (*b).value;
332 	if (!is_zero(diff))
333 	  new_coord.push_back(monomial<gen>(diff,pow_a));
334 	++a;
335 	++b;
336       }
337     }
338   }
339 
operator -(const polynome & th,const polynome & other)340   polynome operator - (const polynome & th,const polynome & other) {
341 #ifdef TIMEOUT
342     control_c();
343 #endif
344     if (ctrl_c || interrupted) {
345       interrupted = true; ctrl_c=false;
346       return monomial<gen>(gensizeerr(gettext("Stopped by user interruption.")),th.dim);
347     }
348     // Tensor addition
349     vector< monomial<gen> >::const_iterator a=th.coord.begin();
350     vector< monomial<gen> >::const_iterator a_end=th.coord.end();
351     vector< monomial<gen> >::const_iterator b=other.coord.begin();
352     vector< monomial<gen> >::const_iterator b_end=other.coord.end();
353     if (b == b_end) {
354       return th;
355     }
356     polynome res(th.dim,th);
357     Sub<gen>(a,a_end,b,b_end,res.coord,th.is_strictly_greater);
358     return res;
359   }
360 
mulpoly(const polynome & th,const gen & fact0,polynome & res)361   void mulpoly(const polynome & th,const gen & fact0,polynome & res){
362     if (&th!=&res)
363       res.coord.clear();
364     gen fact=fact0;
365     if (fact.type!=_MOD && fact.type!=_USER && !th.coord.empty() && th.coord.front().value.type==_MOD){
366       fact = makemod(fact,*(th.coord.front().value._MODptr+1));
367     }
368     if (!is_zero(fact)){
369       vector< monomial<gen> >::const_iterator a = th.coord.begin();
370       vector< monomial<gen> >::const_iterator a_end = th.coord.end();
371       Mul<gen>(a,a_end,fact,res.coord);
372     }
373   }
374 
operator *(const polynome & th,const gen & fact)375   polynome operator * (const polynome & th, const gen & fact){
376 #ifdef TIMEOUT
377     control_c();
378 #endif
379     if (ctrl_c || interrupted) {
380       interrupted = true; ctrl_c=false;
381       return monomial<gen>(gensizeerr(gettext("Stopped by user interruption.")),th.dim);
382     }
383     // Tensor constant multiplication
384     if (fact.type!=_MOD && fact==gen(1))
385       return th;
386     polynome res(th.dim,th);
387     mulpoly(th,fact,res);
388     return res;
389   }
390 
391 #ifdef NSPIRE
operator <<(nio::ios_base<T> & os,const int_unsigned & i)392   template<class T> nio::ios_base<T> & operator << (nio::ios_base<T> & os,const int_unsigned & i){
393     return os << i.g << ":" << i.u ;
394   }
395 #else
operator <<(ostream & os,const int_unsigned & i)396   ostream & operator << (ostream & os,const int_unsigned & i){
397     return os << i.g << ":" << i.u ;
398   }
399 #endif
400 
operator <(const int_unsigned & gu1,const int_unsigned & gu2)401   inline bool operator < (const int_unsigned & gu1,const int_unsigned & gu2){
402     return gu1.u > gu2.u;
403   }
404 
405   template <class U>
convert(const polynome & p,const index_t & deg,std::vector<T_unsigned<int,U>> & v,int reduce)406   static bool convert(const polynome & p,const index_t & deg,std::vector< T_unsigned<int,U> >  & v,int reduce){
407     std::vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
408     v.clear();
409     v.reserve(itend-it);
410     T_unsigned<int,U> gu;
411     U u;
412     index_t::const_iterator itit,ditbeg=deg.begin(),ditend=deg.end(),dit;
413     if (reduce==0){
414       for (;it!=itend;++it){
415 	itit=it->index.begin();
416 	u=U(*itit);
417 	for (dit=ditbeg+1,++itit;dit!=ditend;++itit,++dit)
418 	  u=u*U(*dit)+U(*itit);
419 	gu.u=u;
420 	if (it->value.type!=_INT_)
421 	  return false;
422 	gu.g=it->value.val;
423 	v.push_back(gu);
424       }
425       return true;
426     }
427     for (;it!=itend;++it){
428       itit=it->index.begin();
429       u=U(*itit);
430       for (dit=ditbeg+1,++itit;dit!=ditend;++itit,++dit)
431 	u=u*U(*dit)+U(*itit);
432       gu.u=u;
433       int tmp=it->value.val;
434       if (it->value.type==_INT_ && 2*tmp<=reduce && -2*tmp<reduce)
435 	gu.g=tmp;
436       else {
437 	gen tmp(smod(it->value,reduce));
438 	if (tmp.type!=_INT_)
439 	  return false;
440 	gu.g=tmp.val;
441       }
442       v.push_back(gu);
443     }
444     return true;
445   }
446 
447   template<class U>
convert(const std::vector<T_unsigned<int,U>> & v,const index_t & deg,polynome & p)448   static void convert(const std::vector< T_unsigned<int,U> > & v,const index_t & deg,polynome & p){
449     typename std::vector< T_unsigned<int,U> >::const_iterator it=v.begin(),itend=v.end();
450     index_t::const_reverse_iterator ditbeg=deg.rbegin(),ditend=deg.rend(),dit;
451     p.dim=ditend-ditbeg;
452     p.coord.clear();
453     p.coord.reserve(itend-it);
454     U u;
455     index_t i(p.dim);
456     int k;
457     for (;it!=itend;++it){
458       u=it->u;
459       for (k=p.dim-1,dit=ditbeg;dit!=ditend;++dit,--k){
460 	i[k]=u % unsigned(*dit);
461 	u = u/unsigned(*dit);
462       }
463       p.coord.push_back(monomial<gen>(it->g,i));
464     }
465   }
466 
467 
468   template <class T,class U>
convert(const vector<T_unsigned<T,U>> & source,vector<T_unsigned<gen,U>> & target)469   static void convert(const vector< T_unsigned<T,U> > & source,vector< T_unsigned<gen,U> > & target){
470     target.clear();
471     typename vector< T_unsigned<T,U> >::const_iterator it=source.begin(),itend=source.end();
472     target.reserve(itend-it);
473     for (;it!=itend;++it)
474       target.push_back(T_unsigned<gen,U>(it->g,it->u));
475   }
476 
ichrem_smod(mpz_t * Az,mpz_t * Bz,mpz_t * iz,mpz_t * tmpz,const gen & i,const gen & j)477   static gen ichrem_smod(mpz_t * Az,mpz_t * Bz,mpz_t * iz,mpz_t * tmpz,const gen & i,const gen & j){
478     if (i.type==_ZINT)
479       mpz_set(*iz,*i._ZINTptr);
480     else
481       mpz_set_si(*iz,i.val);
482     // i-j
483     if (j.type==_INT_){
484       if (j.val>0)
485 	mpz_sub_ui(*tmpz,*iz,j.val);
486       else
487 	mpz_add_ui(*tmpz,*iz,-j.val);
488     }
489     else
490       mpz_sub(*tmpz,*iz,*j._ZINTptr);
491     // times B +i
492     mpz_addmul(*iz,*tmpz,*Bz);
493     // mod A
494     mpz_mod(*tmpz,*iz,*Az);
495     // compare with *tmpz-Az
496     mpz_sub(*iz,*tmpz,*Az);
497     mpz_neg(*iz,*iz);
498     ref_mpz_t *res = new ref_mpz_t(GIAC_MPZ_INIT_SIZE);
499     if (mpz_cmp(*iz,*tmpz)>=0) // use *tmpz
500       mpz_set(res->z,*tmpz);
501     else {
502       mpz_set(res->z,*iz);
503       mpz_neg(res->z,res->z);
504     }
505     return res;
506   }
507 
ichrem_smod(mpz_t * Az,mpz_t * Bz,mpz_t * iz,mpz_t * tmpz,longlong i,longlong j)508   static gen ichrem_smod(mpz_t * Az,mpz_t * Bz,mpz_t * iz,mpz_t * tmpz,longlong i,longlong j){
509     if (i==j)
510       return i;
511     longlong2mpz(i,iz);
512     // longlong2mpz(i-j,tmpz); does not work since i-j might overflow
513     longlong2mpz(j,tmpz);
514     mpz_sub(*tmpz,*iz,*tmpz);
515     // i+=B*(i-j)
516     mpz_addmul(*iz,*tmpz,*Bz);
517     // mod A
518     mpz_mod(*tmpz,*iz,*Az);
519     // compare with *tmpz-Az
520     mpz_sub(*iz,*tmpz,*Az);
521     mpz_neg(*iz,*iz);
522     ref_mpz_t *res =  new ref_mpz_t(GIAC_MPZ_INIT_SIZE);
523     int test=mpz_cmp(*iz,*tmpz);
524     if (test>=0) // use *tmpz
525       mpz_set(res->z,*tmpz);
526     else {
527       mpz_set(res->z,*iz);
528       mpz_neg(res->z,res->z);
529     }
530     return res;
531   }
532 
533 #if 0
534   // set i to i+((((j-i)* mod addprime)*u) mod addprime)*targetprime, inplace operation
535   // (where u*targetprime+unknow_integer*addprime=1)
536   static void ichrem_smod_inplace(int addprime,int u,const gen &targetprime,gen & i,const gen & j){
537     longlong tmp=longlong(j.val)-((i.type==_ZINT)?modulo(*i._ZINTptr,addprime):i.val);
538     tmp=(tmp*u)%addprime;
539     if (targetprime.type==_ZINT && i.type==_ZINT){
540       if (tmp>0)
541 	mpz_addmul_ui(*i._ZINTptr,*targetprime._ZINTptr,int(tmp));
542       else
543 	mpz_submul_ui(*i._ZINTptr,*targetprime._ZINTptr,-int(tmp));
544     }
545     else
546       i += int(tmp)*targetprime;
547   }
548 
549   static gen ichrem_smod(int addprime,int u,const gen &targetprime,longlong i,int j,mpz_t * tmpz){
550     longlong tmp=longlong(j)-i%addprime;
551     tmp=(tmp*u)%addprime;
552     gen I(i);
553     I.uncoerce();
554     // now return I+tmp*targetprime
555     if (targetprime.type==_INT_){
556       tmp *= targetprime.val; // no overflow since tmp<2^31 and targetprime.val also
557       longlong2mpz(tmp,tmpz);
558       mpz_add(*I._ZINTptr,*I._ZINTptr,*tmpz);
559     }
560     else {
561       if (tmp>=0)
562 	mpz_addmul_ui(*I._ZINTptr,*targetprime._ZINTptr,tmp);
563       else
564 	mpz_submul_ui(*I._ZINTptr,*targetprime._ZINTptr,-tmp);
565     }
566     return I;
567   }
568 #endif
569 
570   // set i to i+(i-j)*B mod A, inplace operation
ichrem_smod_inplace(mpz_t * Az,mpz_t * Bz,mpz_t * iz,mpz_t * tmpz,gen & i,const gen & j)571   void ichrem_smod_inplace(mpz_t * Az,mpz_t * Bz,mpz_t * iz,mpz_t * tmpz,gen & i,const gen & j){
572     if (i==j)
573       return;
574     if (i.type==_ZINT)
575       mpz_set(*iz,*i._ZINTptr);
576     else
577       mpz_set_si(*iz,i.val);
578     // i-j
579     if (j.type==_INT_){
580       if (j.val>0)
581 	mpz_sub_ui(*tmpz,*iz,j.val);
582       else
583 	mpz_add_ui(*tmpz,*iz,-j.val);
584     }
585     else
586       mpz_sub(*tmpz,*iz,*j._ZINTptr);
587     // times B +i
588     mpz_addmul(*iz,*tmpz,*Bz);
589     // mod A
590     mpz_mod(*tmpz,*iz,*Az);
591     // compare with *tmpz-Az
592     mpz_sub(*iz,*tmpz,*Az);
593     mpz_neg(*iz,*iz);
594     if (i.type==_ZINT){
595       if (mpz_cmp(*iz,*tmpz)>=0) // use *tmpz
596 	mpz_set(*i._ZINTptr,*tmpz);
597       else {
598 	mpz_set(*i._ZINTptr,*iz);
599 	mpz_neg(*i._ZINTptr,*i._ZINTptr);
600       }
601     }
602     else {
603       ref_mpz_t *res = new ref_mpz_t(GIAC_MPZ_INIT_SIZE);
604       if (mpz_cmp(*iz,*tmpz)>=0) // use *tmpz
605 	mpz_set(res->z,*tmpz);
606       else {
607 	mpz_set(res->z,*iz);
608 	mpz_neg(res->z,res->z);
609       }
610       i=res;
611     }
612   }
613 
614 #if 0
615   // smod(B*(i-j)+i,A);
616   static gen ichrem_smod(const gen & A,const gen & B,const gen & i,const gen & j){
617     if (i==j)
618       return i;
619     if (A.type!=_ZINT || B.type!=_ZINT)
620       return smod(B*(i-j)+i,A);
621     mpz_t * Az=A._ZINTptr,*Bz=B._ZINTptr,iz,tmpz;
622     ref_mpz_t *res = new ref_mpz_t(GIAC_MPZ_INIT_SIZE);
623     mpz_init(tmpz);
624     if (i.type==_ZINT)
625       mpz_init_set(iz,*i._ZINTptr);
626     else
627       mpz_init_set_si(iz,i.val);
628     // i-j
629     if (j.type==_INT_){
630       if (j.val>0)
631 	mpz_sub_ui(tmpz,iz,j.val);
632       else
633 	mpz_add_ui(tmpz,iz,-j.val);
634     }
635     else
636       mpz_sub(tmpz,iz,*j._ZINTptr);
637     // times B +i
638     mpz_addmul(iz,tmpz,*Bz);
639     // mod A
640     mpz_mod(tmpz,iz,*Az);
641     // compare with tmpz-Az
642     mpz_sub(iz,tmpz,*Az);
643     mpz_neg(iz,iz);
644     if (mpz_cmp(iz,tmpz)>0) // use tmpz
645       mpz_set(res->z,tmpz);
646     else {
647       mpz_set(res->z,iz);
648       mpz_neg(res->z,res->z);
649     }
650     mpz_clear(iz);
651     mpz_clear(tmpz);
652     return res;
653   }
654 
655   static gen ichrem_smod(const gen & A,const gen & B,longlong i,longlong j){
656     // return smod((i-j)*B+i,A);
657     if (i==j)
658       return i;
659     return ichrem_smod(A,B,gen(i),gen(j));
660   }
661 #endif
662 
663   template<class T,class U>
ichrem(const vector<T_unsigned<T,U>> & add,int addprime,const vector<T_unsigned<longlong,U>> & init,vector<T_unsigned<gen,U>> & target,gen & targetprime)664   static void ichrem(const vector< T_unsigned<T,U> > & add,int addprime,const vector< T_unsigned<longlong,U> > & init,vector< T_unsigned<gen,U> > & target,gen & targetprime){
665     gen A,B,d;
666     egcd(addprime,targetprime,A,B,d);
667 #ifndef NO_STDEXCEPT
668     if (!is_one(d)) // should not happen
669       setsizeerr();
670 #endif
671     // addprime*A+targetprime*B=1
672     // find c such that c=it->g mod targetprime and c=jt->g mod addprime
673     // it->g + v*targetprime = jt->g + u*addprime
674     // it->g - jt->g = u*addprime - v*targetprime
675     // v=(jt->g-it->g)*B
676     // hence c=it->g+(jt->g-it->g)*B*targetprime mod addprime*targetprime
677     // IMPROVE c=it->g+(((jt->g-it->g) mod addprime)*B mod addprime)*targetprime
678     // int b=B.type==_ZINT?mpz_get_si(*B._ZINTptr):B.val;
679     A=addprime*targetprime;
680     B=-targetprime*B;
681     mpz_t z1,z2;
682     mpz_init(z1);
683     mpz_init(z2);
684     if (A.type!=_ZINT)
685       A.uncoerce();
686     if (B.type!=_ZINT)
687       B.uncoerce();
688     typename vector< T_unsigned<T,U> >::const_iterator jt=add.begin(),jtend=add.end();
689     typename vector< T_unsigned<longlong,U> >::const_iterator kt=init.begin(),ktend=init.end();
690     typename vector< T_unsigned<gen,U> >::iterator it=target.begin(),itend=target.end();
691     if (it==itend){
692       target.reserve(ktend-kt);
693       for (;kt!=ktend && jt!=jtend;){
694 	if (kt->u==jt->u){
695 	  // it->g=smod(B*(it->g-jt->g)+it->g,A);
696 	  // target.push_back(T_unsigned<gen,U>(ichrem_smod(addprime,b,targetprime,kt->g,jt->g,&z1),jt->u));
697 	  target.push_back(T_unsigned<gen,U>(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,kt->g,jt->g),jt->u));
698 	  ++kt; ++jt;
699 	}
700 	else {
701 	  if (kt->u>jt->u){
702 	    target.push_back(T_unsigned<gen,U>(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,kt->g,0),kt->u));
703 	    ++kt;
704 	  }
705 	  else {
706 	    target.push_back(T_unsigned<gen,U>(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,0,jt->g),jt->u));
707 	    ++jt;
708 	  }
709 	}
710       }
711       for (;jt!=jtend;++jt)
712 	target.push_back(T_unsigned<gen,U>(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,0,jt->g),jt->u));
713       for (;kt!=ktend;++jt)
714 	target.push_back(T_unsigned<gen,U>(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,kt->g,0),kt->u));
715     }
716     else {
717       for (;it!=itend && jt!=jtend;){
718 	if (it->u==jt->u){
719 	  // it->g=smod(B*(it->g-jt->g)+it->g,A);
720 	  ichrem_smod_inplace(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,jt->g);
721 	  // ichrem_smod_inplace(addprime,b,targetprime,it->g,jt->g);
722 	  // it->g=ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,jt->g);
723 	  ++it; ++jt;
724 	}
725 	else {
726 	  if (it->u>jt->u){
727 	    ichrem_smod_inplace(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,0);
728 	    // ichrem_smod_inplace(addprime,b,targetprime,it->g,0);
729 	    // it->g=ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,0);
730 	    ++it;
731 	  }
732 	  else {
733 	    vector< T_unsigned<gen,U> > copie(it,itend);
734 	    target.erase(it,itend);
735 	    it=copie.begin(); itend=copie.end();
736 	    for (;it!=itend;){
737 	      if (jt==jtend || it->u>jt->u){
738 		it->g=ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,0);
739 		target.push_back(*it);
740 		++it;
741 	      }
742 	      else {
743 		++jt;
744 		if (it->u==jt->u){
745 		  target.push_back(T_unsigned<gen,U>(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,jt->g),it->u));
746 		  ++it;
747 		}
748 		else
749 		  target.push_back(T_unsigned<gen,U>(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,0,jt->g),jt->u));
750 	      }
751 	    }
752 	    break;
753 	  }
754 	}
755       }
756       for (;jt!=jtend;++jt)
757 	target.push_back(T_unsigned<gen,U>(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,0,jt->g),jt->u));
758       for (;it!=itend;++it){
759 	// it->g=ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,0);
760 	ichrem_smod_inplace(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,0);
761 	// ichrem_smod_inplace(addprime,b,targetprime,it->g,0);
762       }
763     } // end target empty at beginning
764     targetprime = addprime*targetprime;
765     mpz_clear(z1);
766     mpz_clear(z2);
767   }
768 
769 #ifdef INT128
770   template<class U>
smod(vector<T_unsigned<int128_t,U>> & target,int prime)771   static void smod(vector< T_unsigned<int128_t,U> > & target,int prime){
772     typename vector< T_unsigned<int128_t,U> >::iterator it=target.begin(),itend=target.end();
773     for (;it!=itend;++it){
774       it->g %= prime;
775     }
776   }
777 #endif
778 
779   template<class U>
smod(const vector<T_unsigned<longlong,U>> & source,vector<T_unsigned<longlong,U>> & target,int prime)780   static void smod(const vector< T_unsigned<longlong,U> > & source,vector< T_unsigned<longlong,U> > & target,int prime){
781     if (&target==&source){
782       typename vector< T_unsigned<longlong,U> >::iterator it=target.begin(),itend=target.end();
783       for (;it!=itend;++it){
784         it->g %= prime;
785         if (!it->g){
786           vector< T_unsigned<longlong,U> > copie(target);
787 
788 #ifndef BESTA_OS
789           smod(copie,target,prime);
790 #else
791 
792           // &copie != &target (by definition) so the following is
793           // substituted from below as the Kiel ARM compiler does
794           // not support this sort of recursive template expansion.
795 
796 	  copie.clear();
797 	  typename vector< T_unsigned<longlong,U> >::const_iterator it=source.begin(),itend=source.end();
798           copie.reserve(itend-it);
799           longlong res;
800           for (;it!=itend;++it){
801             res=it->g % prime;
802             if (res)
803                copie.push_back(T_unsigned<longlong,U>(res,it->u));
804           }
805 	  target=copie;
806 #endif
807 
808           break;
809         }
810       }
811       return;
812     }
813     target.clear();
814     typename vector< T_unsigned<longlong,U> >::const_iterator it=source.begin(),itend=source.end();
815     target.reserve(itend-it);
816     longlong res;
817     for (;it!=itend;++it){
818       res=it->g % prime;
819       if (res)
820 	target.push_back(T_unsigned<longlong,U>(res,it->u));
821     }
822   }
823 
824 #ifdef INT128
825   template <class U>
convert_int128(const vector<T_unsigned<longlong,U>> & p1d,vector<T_unsigned<int128_t,U>> & p1D)826   static void convert_int128(const vector< T_unsigned<longlong,U> > & p1d,vector< T_unsigned<int128_t,U> > & p1D){
827     typename vector< T_unsigned<longlong,U> >::const_iterator it=p1d.begin(),itend=p1d.end();
828     p1D.clear();
829     p1D.reserve(itend-it);
830     for (;it!=itend;++it)
831       p1D.push_back(T_unsigned<int128_t,U>(it->g,it->u));
832   }
833 #endif
834 
addsamepower_gen(std::vector<monomial<gen>>::const_iterator & it,std::vector<monomial<gen>>::const_iterator & itend,std::vector<monomial<gen>> & new_coord)835   void addsamepower_gen(std::vector< monomial<gen> >::const_iterator & it,
836 			std::vector< monomial<gen> >::const_iterator & itend,
837 			std::vector< monomial<gen> > & new_coord){
838     gen res;
839     while (it!=itend){
840       res=(*it).value;
841       index_m pow=(*it).index;
842       ++it;
843       while ( (it!=itend) && ((*it).index==pow)){
844 	res=res+(*it).value;
845 	++it;
846       }
847       if (!is_zero(res))
848 	new_coord.push_back(monomial<gen>(res, pow));
849     }
850   }
851 
Mul_gen(std::vector<monomial<gen>>::const_iterator & ita,std::vector<monomial<gen>>::const_iterator & ita_end,std::vector<monomial<gen>>::const_iterator & itb,std::vector<monomial<gen>>::const_iterator & itb_end,std::vector<monomial<gen>> & new_coord,bool (* is_strictly_greater)(const index_m &,const index_m &),const std::pointer_to_binary_function<const monomial<gen> &,const monomial<gen> &,bool> m_is_strictly_greater)852   void Mul_gen ( std::vector< monomial<gen> >::const_iterator & ita,
853 		 std::vector< monomial<gen> >::const_iterator & ita_end,
854 		 std::vector< monomial<gen> >::const_iterator & itb,
855 		 std::vector< monomial<gen> >::const_iterator & itb_end,
856 		 std::vector< monomial<gen> > & new_coord,
857 		 bool (* is_strictly_greater)( const index_m &, const index_m &),
858 		 const std::pointer_to_binary_function < const monomial<gen> &, const monomial<gen> &, bool> m_is_strictly_greater
859 	     ) {
860     if (ita==ita_end || itb==itb_end){
861       new_coord.clear();
862       return;
863     }
864     int asize=int(ita_end-ita),bsize=int(itb_end-itb);
865     int d=int(ita->index.size());
866     std::vector< monomial<gen> > multcoord;
867     multcoord.reserve(asize*bsize); // correct for sparse polynomial
868     std::vector< monomial<gen> >::const_iterator ita_begin = ita,itb_begin=itb ;
869     index_m old_pow=(*ita).index+(*itb).index;
870     gen res( 0);
871     for ( ; ita!=ita_end; ++ita ){
872       std::vector< monomial<gen> >::const_iterator ita_cur=ita;
873       std::vector< monomial<gen> >::const_iterator itb_cur=itb;
874       for (;itb_cur!=itb_end;--ita_cur,++itb_cur) {
875 	index_m cur_pow=(*ita_cur).index+(*itb_cur).index;
876 	if (cur_pow!=old_pow){
877 	  if (!is_zero(res))
878 	    multcoord.push_back( monomial<gen>(res ,old_pow ));
879 	  res=((*ita_cur).value) * ((*itb_cur).value);
880 	  old_pow=cur_pow;
881 	}
882 	else
883 	  res=res+((*ita_cur).value) * ((*itb_cur).value);
884 	if (ita_cur==ita_begin)
885 	  break;
886       }
887     }
888     --ita;
889     ++itb;
890     for ( ; itb!=itb_end;++itb){
891       std::vector< monomial<gen> >::const_iterator ita_cur=ita;
892       std::vector< monomial<gen> >::const_iterator itb_cur=itb;
893       for (;itb_cur!=itb_end;--ita_cur,++itb_cur) {
894 	index_m cur_pow=(*ita_cur).index+(*itb_cur).index;
895 	if (cur_pow!=old_pow){
896 	  if (!is_zero(res))
897 	    multcoord.push_back( monomial<gen>(res ,old_pow ));
898 	  res=((*ita_cur).value) * ((*itb_cur).value);
899 	  old_pow=cur_pow;
900 	}
901 	else
902 	  res=res+((*ita_cur).value) * ((*itb_cur).value);
903 
904 	if (ita_cur==ita_begin)
905 	  break;
906       }
907     }
908     // push last monomial
909     if (!is_zero(res))
910       multcoord.push_back( monomial<gen>(res ,old_pow ));
911     // sort by asc. power
912 #if 1 // def NSPIRE
913     sort( multcoord.begin(),multcoord.end(),sort_helper<gen>(m_is_strictly_greater));
914 #else
915     sort( multcoord.begin(),multcoord.end(),m_is_strictly_greater);
916 #endif
917     std::vector< monomial<gen> >::const_iterator it=multcoord.begin();
918     std::vector< monomial<gen> >::const_iterator itend=multcoord.end();
919     // adjust result size
920     // statistics about polynomial density
921     // a dense poly of deg. aa and d variables has binomial(aa+d,d) monomials
922     // we need to reserve at most asize*bsize
923     // but less for dense polynomials since
924     // binomial(aa+d,d)*binomial(bb+d,d) > binomial(aa+bb+d,d)
925     int aa=total_degree(ita_begin->index),bb=total_degree(itb_begin->index);
926     double r;
927     double factoriald=std::log(evalf_double(factorial(d+1),1,context0)._DOUBLE_val);
928     // double factorialaa=std::lgamma(aa+1),factorialbb=std::lgamma(bb+1);
929     // double factorialaad=std::lgamma(aa+d+1),factorialbbd=std::lgamma(bb+d+1);
930     double factorialaabbd=std::log(evalf_double(factorial(aa+bb+d+1),1,context0)._DOUBLE_val),
931       factorialaabb=std::log(evalf_double(factorial(aa+bb+1),1,context0)._DOUBLE_val);
932     r=std::exp(factorialaabbd-(factorialaabb+factoriald));
933     if (debug_infolevel>1)
934       CERR << "// " << CLOCK() << " Mul degree " << aa << "+" << bb << " size " << asize << "*" << bsize << "=" << asize*bsize << " max " << r << '\n';
935     new_coord.clear();
936     if (my_isinf(r) || my_isnan(r) || r>1e9)
937       new_coord.reserve(itend-it);
938     else
939       new_coord.reserve(giacmin(int(r),int(itend-it)));
940     // add terms with same power
941     addsamepower_gen(it,itend,new_coord);
942     if (debug_infolevel>1)
943       CERR << "// Actual mul size " << new_coord.size() << '\n';
944   }
945 
is_integer_poly(const polynome & p,bool intonly)946   bool is_integer_poly(const polynome & p,bool intonly){
947     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
948     for (;it!=itend;++it){
949       if (it->value.type==_INT_) continue;
950       if (intonly) return false;
951       if (it->value.type==_ZINT) continue;
952       // if (it->type==_CPLX && is_exactly_zero(*(it->_CPLXptr+1))) continue;
953       return false;
954       // if (!is_integer(*it)) return false;
955     }
956     return true;
957   }
958 
polynome2poly1(const polynome & p,const index_t & pdeg,const index_t & deg,vecteur & v)959   bool polynome2poly1(const polynome & p,const index_t & pdeg,const index_t &deg,vecteur & v){
960     v.clear();
961     int tot=0;
962     for (size_t i=0;i<deg.size();++i){
963       tot *= deg[i];
964       tot += pdeg[i];
965     }
966     v.resize(tot+1);
967     std::vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
968     int u;
969     index_t::const_iterator itit,ditbeg=deg.begin(),ditend=deg.end(),dit;
970     gen tmp;
971     for (;it!=itend;++it){
972       u=0;
973       itit=it->index.begin();
974       for (dit=ditbeg;dit!=ditend;++itit,++dit)
975 	u=u*(*dit)+(*itit);
976       if (!is_integer(it->value.type))
977 	return false;
978       v[u]=it->value;
979     }
980     return true;
981   }
982 
poly12polynome(const vecteur & v,const index_t & deg,polynome & p)983   bool poly12polynome(const vecteur & v,const index_t & deg,polynome & p){
984     const_iterateur it=v.begin(),itend=v.end();
985     index_t::const_reverse_iterator ditbeg=deg.rbegin(),ditend=deg.rend(),dit;
986     p.dim=ditend-ditbeg;
987     p.coord.clear();
988     p.coord.reserve(itend-it);
989     int u,U=int(v.size());
990     index_t i(p.dim);
991     int k;
992     for (--itend;itend>=it;--itend){
993       gen g=*itend;
994       if (is_zero(g))
995 	continue;
996       u=int(itend-it);
997       for (k=p.dim-1,dit=ditbeg;dit!=ditend;++dit,--k){
998 	i[k]=u % unsigned(*dit);
999 	u = u/unsigned(*dit);
1000       }
1001       p.coord.push_back(monomial<gen>(g,i));
1002     }
1003     return true;
1004   }
1005 
int32_modularize(polynome & res,const gen & m)1006   void int32_modularize(polynome & res,const gen &m){
1007     vector< monomial<gen> >::iterator it=res.coord.begin(),itend=res.coord.end();
1008     for (;it!=itend;++it){
1009       if (it->value.type==_INT_){
1010 	int r=it->value.val;
1011 	r += (unsigned(r)>>31)*m.val; // make positive
1012 	r -= (unsigned((m.val>>1)-r)>>31)*m.val;
1013 	it->value=makemodquoted(r,m);
1014       }
1015     }
1016   }
1017 
1018   // Fast multiplication using hash maps, might also use an int for reduction
1019   // but there is no garantee that res is smod-ed modulo reduce
mulpoly(const polynome & th,const polynome & other,polynome & res,const gen & reduce)1020   void mulpoly(const polynome & th, const polynome & other,polynome & res,const gen & reduce){
1021 #ifdef TIMEOUT
1022     control_c();
1023 #endif
1024     if (ctrl_c || interrupted) {
1025       interrupted = true; ctrl_c=false;
1026       res=monomial<gen>(gensizeerr(gettext("Stopped by user interruption.")),th.dim);
1027       return;
1028     }
1029     /*
1030     if (th.dim==12)
1031       CERR << "* begin " << CLOCK() << " " << th.coord.size() << "*" << other.coord.size() << '\n';
1032     */
1033     // Multiplication
1034     vector< monomial<gen> >::const_iterator ita = th.coord.begin();
1035     vector< monomial<gen> >::const_iterator ita_end = th.coord.end();
1036     vector< monomial<gen> >::const_iterator itb = other.coord.begin();
1037     vector< monomial<gen> >::const_iterator itb_end = other.coord.end();
1038     //  COUT << coord.size() << " " << (int) ita_end - (int) ita << " " << sizeof(monomial<gen>) << '\n' ;
1039     // first some trivial cases
1040     if (ita==ita_end || is_one(other)){
1041       res=th;
1042       return;
1043     }
1044     if (itb==itb_end || is_one(th)){
1045       res=other;
1046       return ;
1047     }
1048     index_t d1=th.degree(),d2=other.degree(),d(th.dim);
1049     double d10,d20;
1050     if ( 0 &&
1051 	 th.dim==1
1052 	 && (d10=d1[0])>=FFTMUL_SIZE && (d20=d2[0])>=FFTMUL_SIZE && (ita_end-ita)*double(itb_end-itb)>(d10+d20)*std::log(double(d10+d20))
1053 	 && is_integer_poly(th,false) && is_integer_poly(other,false)
1054 	 ){
1055       modpoly A=polynome2poly1(th,1);
1056       modpoly B=polynome2poly1(other,1);
1057       modpoly C;
1058       mulmodpoly(A,B,0,C);
1059       poly12polynome(C,1,res,1);
1060       return;
1061     }
1062     double lagrtime=1.,sumdeg=0.;
1063     for (int i=0;i<th.dim;++i){
1064       int tmp=(d1[i]+d2[i]+1);
1065       if (tmp>=(1<<15)){
1066 	res=monomial<gen>(gensizeerr(gettext("Polynomial exponent overflow.")),th.dim);
1067 	return;
1068       }
1069       sumdeg += tmp;
1070       lagrtime *= tmp;
1071     }
1072     d10=lagrtime;
1073     lagrtime *= sumdeg;
1074     // Now look if length a=1 or length b=1, happens frequently
1075     // think of x^3*y^2*z translated to internal form
1076     int c1=int(th.coord.size());
1077     if (c1==1){
1078       res=other.shift(th.coord.front().index,th.coord.front().value);
1079       return ;
1080     }
1081     int c2=int(other.coord.size());
1082     if (c2==1){
1083       res=th.shift(other.coord.front().index,other.coord.front().value);
1084       return;
1085     }
1086     //int t1=th.coord.front().value.type,t2=other.coord.front().value.type;
1087     gen T1=th.coord.front().value,T2=other.coord.front().value;
1088     // gen T1=th.coord[c1/2].value,T2=other.coord[c2/2].value;
1089     int t1=T1.type,t2=T2.type;
1090 #if 1 // does not work if _ext are embedded inside fractions (check done in unext)
1091     if (t1==_EXT || t2==_EXT){
1092       gen minp;
1093       if (t1==_EXT)
1094 	minp=*(T1._EXTptr+1);
1095       else
1096 	minp=*(T2._EXTptr+1);
1097       polynome p1m,p2m,pm(th.dim);
1098       if (minp.type==_VECT && unext(th,minp,p1m) && unext(other,minp,p2m)){
1099 	mulpoly(p1m,p2m,pm,0);
1100 	ext(pm,minp,res);
1101 	//Mul<gen>(ita,ita_end,itb,itb_end,pm.coord,th.is_strictly_greater,th.m_is_strictly_greater);
1102 	//if (!(pm-res).coord.empty())
1103 	//CERR << "err" << th << '\n' << other << '\n' << pm-res << '\n';
1104 	return;
1105       }
1106     } // end EXT
1107     if (1 && (t1==_MOD || t2==_MOD)){
1108       gen m=t1==_MOD?*(T1._MODptr+1):*(T2._MODptr+1);
1109       if (m.type==_INT_){
1110 	polynome thm,otherm;
1111 	unmodularize(th,thm);
1112 	unmodularize(other,otherm);
1113 	mulpoly(thm,otherm,res,m);
1114 	int32_modularize(res,m);
1115 	return;
1116       }
1117     }
1118 #endif
1119 #ifdef NO_TEMPLATE_MULTGCD
1120 #ifdef FXCG
1121     Mul_gen(ita,ita_end,itb,itb_end,res.coord,th.is_strictly_greater,th.m_is_strictly_greater);
1122 #else
1123     Mul<gen>(ita,ita_end,itb,itb_end,res.coord,th.is_strictly_greater,th.m_is_strictly_greater);
1124     // Mul_gen(ita,ita_end,itb,itb_end,res.coord,th.is_strictly_greater,th.m_is_strictly_greater);
1125 #endif
1126     return;
1127 #else
1128     if (
1129 	//true || // used for debugging with small poly
1130 	c1>50 || c2 >50 || (c1>7 && c2>7)
1131 	){
1132       // Degree info, try to multiply the polys using integer for the exponents
1133       ulonglong ans=1,pid1=1,pid2=1;
1134       for (int i=0;i<th.dim;++i){
1135 	pid1 = pid1*unsigned(d1[i]+1);
1136 	pid2 = pid2*unsigned(d2[i]+1);
1137       }
1138       for (int i=0;i<th.dim;++i){
1139 	d[i]=d1[i]+d2[i]+1;
1140 	ans = ans*unsigned(d[i]);
1141 	if (ans/RAND_MAX>RAND_MAX)
1142 	  break;
1143       }
1144       // ans/d[th.dim-1] == degree 1 with respect to main var and 0 for other
1145       // guess size of result
1146       // compare product of d1[i] with c1 and product of d2[i] with c2
1147       // for sparness factor
1148       double d1sparness=double(c1)/pid1;
1149       double d2sparness=double(c2)/pid2;
1150       ulonglong c1c2= ulonglong(c1)*c2;
1151       if (ans<c1c2)
1152 	c1c2=ans;
1153       c1c2 = unsigned(std::sqrt(d1sparness*d2sparness)*c1c2);
1154       if (c1c2> (1<<24) )
1155 	c1c2 = 1 << 24;
1156       // Possible improvement for modular product mod p in an array
1157       // make one of the argument with negative coeffs, the other with positive
1158       // init array with p^2, then type_operator_plus_times_reduce
1159       // could do += p1[]*p2[] and if result <0 add p^2
1160       // ?encode reduce as -p^2, and check sign in do_threadmult in threaded.h
1161       // OR use int128
1162       if (ans<=RAND_MAX) {
1163 	if (reduce.type==_INT_){
1164 	  if (//reduce.val<46340 &&
1165 	      reduce.val>0
1166 	      ){
1167 #if 1
1168 	    longlong maxp1,maxp2;
1169 	    vector< T_unsigned<longlong,unsigned> > p1d,p2d,pd;
1170 	    if (convert_int(th,d,p1d,maxp1) && convert_int(other,d,p2d,maxp2) ){
1171 	      double maxp1p2=double(maxp1)*maxp2;
1172 	      unsigned minc1c2=giacmin(c1,c2);
1173 	      double un63=double(ulonglong (1) << 63);
1174 	      double res_size=double(minc1c2)*maxp1p2;
1175 	      // Check if mod may be done only at the end
1176 	      res_size /= un63;
1177 	      if (res_size<1){
1178 		if (th.dim==1 || !threadmult<longlong,unsigned>(p1d,p2d,pd,unsigned(ans/d[0]),0,size_t(c1c2)))
1179 		  smallmult(p1d,p2d,pd,0,size_t(c1c2));
1180 		smod(pd,pd,reduce.val);
1181 		convert_from<longlong,unsigned>(pd,d,res,false);
1182 	      }
1183 	      else {
1184 #ifdef INT128
1185 		if (res_size<un63){
1186 		  vector< T_unsigned<int128_t,unsigned> > p1D,p2D,pD;
1187 		  convert_int128(p1d,p1D);
1188 		  convert_int128(p2d,p2D);
1189 		  if (th.dim==1 || !threadmult<int128_t,unsigned>(p1D,p2D,pD,ans/d[0],0,c1c2))
1190 		    smallmult<int128_t,unsigned>(p1D,p2D,pD,0,c1c2);
1191 		  smod(pD,reduce.val);
1192 		  convert_from<int128_t,unsigned>(pD,d,res,false);
1193 		}
1194 		else
1195 #endif // INT128
1196 		  {
1197 		    if (th.dim==1 || !threadmult<longlong,unsigned>(p1d,p2d,pd,unsigned(ans/d[0]),reduce.val,size_t(c1c2)))
1198 		      smallmult(p1d,p2d,pd,reduce.val,size_t(c1c2));
1199 		    convert_from<longlong,unsigned>(pd,d,res,false);
1200 		  }
1201 	      }
1202 	      return;
1203 	    } // if convert_int ...
1204 #else
1205 	    // Modular multiplication, convert everything to integers
1206 	    vector< int_unsigned > p1,p2,p;
1207 	    if (convert(th,d,p1,reduce.val) && convert(other,d,p2,reduce.val)){
1208 	      if (reduce.val<46340 && 10*lagrtime<double(c1)*c2*std::log(double(giacmax(c1,c2))))
1209 		smallmulpoly_interpolate(p1,p2,p,d,reduce.val);
1210 	      else {
1211 		if (!threadmult<int,unsigned>(p1,p2,p,ans/d[0],reduce.val,int(c1c2)))
1212 		  smallmult(p1,p2,p,reduce.val,int(c1c2)); // 46340 bound not required?
1213 	      }
1214 	      convert(p,d,res);
1215 	      return ;
1216 	    }
1217 #endif
1218 	  } // end reduce.val>0
1219 	} // end reduce.val==_INT_
1220 	if ( //false
1221 	     (t1==_INT_ || t1==_ZINT) && (t2==_INT_ || t2==_ZINT)
1222 	    ){
1223 	  if (//1||
1224 	      0 &&
1225 	      c1>=FFTMUL_SIZE && c2>=FFTMUL_SIZE && th.dim>1 && d10*std::log(d10)<c1*double(c2)){
1226 	    CERR << CLOCK()*1e-6 << " ?fftmult " << c1 << "*" << c2 << " fft " << d10 << '\n';
1227 #if 1
1228 	    vecteur thv,otherv,resv;
1229 	    polynome2poly1(th,d1,d,thv);
1230 	    polynome2poly1(other,d2,d,otherv);
1231 	    fftmult(thv,otherv,resv,0);
1232 	    poly12polynome(resv,d,res);
1233 #if 0	    // debug
1234 	    polynome res1(res.dim);
1235 	    Mul<gen>(ita,ita_end,itb,itb_end,res1.coord,th.is_strictly_greater,th.m_is_strictly_greater);
1236 	    if (res1!=res)
1237 	      CERR << "fftmult * error " << res-res1 << '\n';
1238 #endif
1239 	    return;
1240 #endif
1241 	  }
1242 	  longlong maxp1,maxp2;
1243 	  // should be T_unsigned<long,unsigned>
1244 	  // instead tmp_operator_times converts longlong args of * to long
1245 	  vector< T_unsigned<longlong,unsigned> > p1d,p2d,pd;
1246 	  if (convert_int(th,d,p1d,maxp1) && convert_int(other,d,p2d,maxp2) ) {
1247 	    double maxp1p2=double(maxp1)*maxp2;
1248 	    unsigned minc1c2=giacmin(c1,c2);
1249 	    double un63=double(ulonglong (1) << 63);
1250 	    double res_size=double(minc1c2)*maxp1p2;
1251 	    // Check number of required primes:
1252 	    res_size /= un63;
1253 	    double nprimes=std::ceil(std::log(res_size)/std::log(2147483647.));
1254 	    if (debug_infolevel>5) CERR << CLOCK() << " primes required " << nprimes << '\n';
1255 #ifdef INT128
1256 	    if (nprimes>0 && nprimes<10){
1257 	      // using multiplications with int128
1258 	      vector< T_unsigned<int128_t,unsigned> > p1D,p2D,pD;
1259 	      convert_int128(p1d,p1D);
1260 	      convert_int128(p2d,p2D);
1261 	      if (th.dim==1 || !threadmult<int128_t,unsigned>(p1D,p2D,pD,ans/d[0],0,c1c2))
1262 		smallmult<int128_t,unsigned>(p1D,p2D,pD,0,c1c2);
1263 	      if (debug_infolevel>5) CERR << CLOCK() << " end int128 mult " << '\n';
1264 	      unsigned pds=pD.size();
1265 	      res_size=double(minc1c2)*maxp1p2/std::pow(2.0,127);
1266 	      if (res_size<1){
1267 		if (debug_infolevel>5) CERR << CLOCK() << " begin result conversion int128_t unsigned" << '\n';
1268 		convert_from<int128_t,unsigned>(pD,d,res,true,threads>1);
1269 		if (debug_infolevel>5) CERR << CLOCK() << " end result conversion" << '\n';
1270 		return;
1271 	      }
1272 	      vector< T_unsigned<gen,unsigned> > target;
1273 	      convert(pD,target);
1274 	      double primed=3037000499.; // floor(2^31.5)
1275 	      primed /= std::sqrt(double(giacmax(minc1c2,4)));
1276 	      gen targetprime = pow(plus_two,128);
1277 	      int prime2=prevprime(int(std::floor(primed))).val;
1278 	      for (;res_size>=1;){
1279                 if (debug_infolevel>5)
1280                   CERR << "prime used " << prime2 << '\n';
1281 		// the product of the two poly mod prime2 can be computed
1282 		// without mod computation
1283 		vector< T_unsigned<longlong,unsigned> > p1add,p2add,add;
1284 		smod(p1d,p1add,prime2);
1285 		smod(p2d,p2add,prime2);
1286 		if (th.dim==1 || !threadmult<longlong,unsigned>(p1add,p2add,add,ans/d[0],0,pds))
1287 		  smallmult(p1add,p2add,add,0,pds);
1288 		smod(add,add,prime2);
1289 		if (debug_infolevel>5) CERR << CLOCK() << " ichrem longlong" << '\n';
1290 		ichrem(add,prime2,pd,target,targetprime); // pd is not used at all here
1291 		res_size /= prime2;
1292 		prime2=prevprime(prime2-2).val;
1293 	      }
1294 	      if (debug_infolevel>5) CERR << CLOCK() << " begin result conversion gen unsigned" << '\n';
1295 	      convert_from<gen,unsigned>(target,d,res,true);
1296 	      if (debug_infolevel>5) CERR << CLOCK() << " end result conversion" << '\n';
1297 	      return;
1298 	    }
1299 #endif // INT128
1300 	    if (
1301 #ifdef HAVE_GMPXX_H
1302 		mpzclass_allowed?nprimes<3.5:nprimes<4.5
1303 #else
1304 		nprimes<4.5
1305 #endif
1306 		){
1307 	      if(debug_infolevel>5) CERR << "Begin smallmult " << CLOCK() << '\n';
1308 	      if (th.dim==1 || !threadmult<longlong,unsigned>(p1d,p2d,pd,unsigned(ans/d[0]),0,size_t(c1c2)))
1309 		smallmult<longlong,unsigned>(p1d,p2d,pd,0,size_t(c1c2));
1310 	      if(debug_infolevel>5) CERR << "End smallmult " << CLOCK() << '\n';
1311 	      unsigned pds=unsigned(pd.size());
1312 	      if ( res_size< 1 ){
1313 		convert_from<longlong,unsigned>(pd,d,res,false);
1314 		return;
1315 	      }
1316 	      // /*
1317 	      else {
1318 		if (debug_infolevel)
1319 		  CERR << nprimes << " primes required" << '\n';
1320 		vector< T_unsigned<gen,unsigned> > target;
1321 		// convert(pd,target);
1322 		int prime1=2147483647;
1323 		double primed=3037000499.; // floor(2^31.5)
1324 		primed /= std::sqrt(double(giacmax(minc1c2,4)));
1325 		// the product of the two poly mod prime2 can be computed
1326 		// without mod computation
1327 		int prime2=prevprime(int(std::floor(primed))).val;
1328 		gen targetprime = pow(plus_two,64);
1329 		for(;res_size>=1;--nprimes){
1330 		  bool withsmod
1331 		    =false;
1332 		    //=true;
1333 		    //=(res_size>std::pow(prime1-1000,nprimes-1)*prime2);
1334 		  if (debug_infolevel>5) CERR << CLOCK() << " prime " << (withsmod?prime1:prime2) << '\n';
1335 		  if (withsmod){
1336 		    vector< int_unsigned > p1,p2,padd;
1337 		    if (!convert(th,d,p1,prime1) || !convert(other,d,p2,prime1)){
1338 #ifndef NO_STDEXCEPT
1339 		      setsizeerr(); // should not happen
1340 #endif
1341 		    }
1342 		    if (th.dim==1 || !threadmult<int,unsigned>(p1,p2,padd,unsigned(ans/d[0]),prime1,pds))
1343 		      smallmult(p1,p2,padd,prime1,pds);
1344 		    if (debug_infolevel>5) CERR << CLOCK() << " ichrem int mod" << '\n';
1345 		    ichrem(padd,prime1,pd,target,targetprime);
1346 		    res_size /= prime1;
1347 		    prime1=prevprime(prime1-2).val;
1348 		  }
1349 		  else {
1350 		    vector< T_unsigned<longlong,unsigned> > p1add,p2add,add;
1351 		    smod(p1d,p1add,prime2);
1352 		    smod(p2d,p2add,prime2);
1353 		    if (th.dim==1 || !threadmult<longlong,unsigned>(p1add,p2add,add,unsigned(ans/d[0]),0,pds))
1354 		      smallmult(p1add,p2add,add,0,pds);
1355 		    smod(add,add,prime2);
1356 		    if (debug_infolevel>5) CERR << CLOCK() << " ichrem longlong" << '\n';
1357 		    ichrem(add,prime2,pd,target,targetprime);
1358 		    res_size /= prime2;
1359 		    prime2=prevprime(prime2-2).val;
1360 		  }
1361 		  if (debug_infolevel>5) CERR << CLOCK() << " ichrem end" << '\n';
1362 		}
1363 		if (debug_infolevel>5) CERR << CLOCK() << '\n';
1364 		convert_from<gen,unsigned>(target,d,res,true);
1365 		if (debug_infolevel>5) CERR << CLOCK() << '\n';
1366 		return;
1367 	      } // end else (some primes are required)
1368 	      // */
1369 	    } // end nprimes<something
1370 	  } // end conversion to longlong possible
1371 	} // end t1==_INT_
1372 #if 0
1373 	if (t1==_MOD || t2==_MOD){
1374 	  gen modulo;
1375 	  if (t1==_MOD)
1376 	    modulo=*(T1._MODptr+1);
1377 	  else
1378 	    modulo=*(T2._MODptr+1);
1379 	  if (modulo.type==_INT_){
1380 	    polynome p1m=unmodularize(th),p2m=unmodularize(other);
1381 	    longlong maxp1,maxp2;
1382 	    vector< T_unsigned<longlong,unsigned> > p1d,p2d,pd;
1383 	    if (convert_int(p1m,d,p1d,maxp1) && convert_int(p2m,d,p2d,maxp2) ){
1384 	      double maxp1p2=double(maxp1)*maxp2;
1385 	      unsigned minc1c2=giacmin(c1,c2);
1386 	      double un63=double(ulonglong (1) << 63);
1387 	      double res_size=double(minc1c2)*maxp1p2;
1388 	      // Check if mod may be done only at the end
1389 	      res_size /= un63;
1390 	      if (res_size<1){
1391 		if (th.dim==1 || !threadmult<longlong,unsigned>(p1d,p2d,pd,unsigned(ans/d[0]),0,size_t(c1c2)))
1392 		  smallmult(p1d,p2d,pd,0,size_t(c1c2));
1393 		smod(pd,pd,modulo.val);
1394 		convert_from<longlong,unsigned>(pd,d,res,false);
1395 	      }
1396 	      else {
1397 #ifdef INT128
1398 		if (res_size<un63){
1399 		  vector< T_unsigned<int128_t,unsigned> > p1D,p2D,pD;
1400 		  convert_int128(p1d,p1D);
1401 		  convert_int128(p2d,p2D);
1402 		  if (th.dim==1 || !threadmult<int128_t,unsigned>(p1D,p2D,pD,ans/d[0],0,c1c2))
1403 		    smallmult<int128_t,unsigned>(p1D,p2D,pD,0,c1c2);
1404 		  smod(pD,modulo.val);
1405 		  convert_from<int128_t,unsigned>(pD,d,res,false);
1406 		}
1407 		else
1408 #endif
1409 		  {
1410 		    if (th.dim==1 || !threadmult<longlong,unsigned>(p1d,p2d,pd,unsigned(ans/d[0]),modulo.val,size_t(c1c2)))
1411 		      smallmult(p1d,p2d,pd,modulo.val,size_t(c1c2));
1412 		    convert_from<longlong,unsigned>(pd,d,res,false);
1413 		  }
1414 	      }
1415 	      // modularize
1416 	      gen g=makemod(res,modulo);
1417 	      if (g.type==_POLY)
1418 		res=*g._POLYptr;
1419 	      else
1420 		res.coord.clear();
1421 	      return;
1422 	    }
1423 	  } // end modulo.type==_INT_
1424 	} // end _MOD types
1425 #endif
1426 	if (t1==_DOUBLE_ && t2==_DOUBLE_){
1427 	  vector< T_unsigned<double,unsigned> > p1d,p2d,pd;
1428 	  if (convert_double(th,d,p1d) && convert_double(other,d,p2d) ){
1429 	    if (th.dim==1 || !threadmult<double,unsigned>(p1d,p2d,pd,unsigned(ans/d[0]),0,size_t(c1c2)))
1430 	      smallmult<double,unsigned>(p1d,p2d,pd,0,size_t(c1c2));
1431 	    convert_from<double,unsigned>(pd,d,res,true);
1432 	    return;
1433 	  }
1434 	}
1435 	// FIXME : the comparison 10*lagr_time is not good at all for e.g int/double args
1436 	if (is_zero(reduce) && 100*lagrtime<double(c1)*c2*std::log(double(giacmax(c1,c2)))){
1437 	  vector< T_unsigned<gen,unsigned> > p1,p2,p;
1438 	  convert<gen,unsigned>(th,d,p1);
1439 	  convert<gen,unsigned>(other,d,p2);
1440 	  smallmulpoly_interpolate<gen,unsigned>(p1,p2,p,d);
1441 	  convert<gen,unsigned>(p,d,res);
1442 	  return;
1443 	}
1444 #ifdef HAVE_GMPXX_H
1445 	if (t1<=_ZINT && t2<=_ZINT && mpzclass_allowed){
1446 	  if (debug_infolevel>1)
1447 	    CERR << "mpz mult convert begin " << CLOCK() << '\n';
1448 	  vector< T_unsigned<myint,unsigned> > p1d,p2d,pd;
1449 	  if (convert_myint(th,d,p1d) && convert_myint(other,d,p2d) ){
1450 	    if (debug_infolevel>1)
1451 	      CERR << "mpz mult begin " << CLOCK() << '\n';
1452 	    // threadmult is slow for heap allocated data because of malloc lock
1453 	    // if (th.dim==1 || !threadmult<myint,unsigned>(p1d,p2d,pd,ans/d[0],0,c1c2))
1454 	      smallmult<myint,unsigned>(p1d,p2d,pd,0,c1c2);
1455 	    if (debug_infolevel>1)
1456 	      CERR << "mpz mult end " << CLOCK() << '\n';
1457 	    convert_from<myint,unsigned>(pd,d,res,false);
1458 	    return;
1459 	  }
1460 	}
1461 #endif
1462 	vector< T_unsigned<gen,unsigned> > p1,p2,p;
1463 	if (debug_infolevel>1)
1464 	  CERR << CLOCK() << "gen mult convert begin " << CLOCK() << '\n';
1465 	convert<gen,unsigned>(th,d,p1);
1466 	convert<gen,unsigned>(other,d,p2);
1467 	if (debug_infolevel>1)
1468 	  CERR << CLOCK() << "gen mult begin " << CLOCK() << '\n';
1469 	// threadmult<gen,.> does not work on multi-CPU (malloc error with GMP data structures) and it would be slow anyway because of malloc locks
1470 	// if (th.dim==1 || !threadmult<gen,unsigned>(p1,p2,p,ans/d[0],0,c1c2))
1471 	smallmult<gen,unsigned>(p1,p2,p,0,size_t(c1c2));
1472 	if (debug_infolevel>1)
1473 	  CERR << CLOCK() << "gen mult end " << CLOCK() << '\n';
1474 	convert<gen,unsigned>(p,d,res);
1475 	if (debug_infolevel>1)
1476 	  CERR << CLOCK() << "gen mult convert end " << CLOCK() << '\n';
1477 	return ;
1478 	// CERR << "Copy " << CLOCK() << " " << copy_number << '\n';
1479 	// if (th.dim==12)
1480 	//  CERR << "sort *unsigned end " << CLOCK() << " " << res.coord.size() << '\n';
1481 	/*
1482 	  polynome save(res);
1483 	  sort(res.coord.begin(),res.coord.end(),th.m_is_strictly_greater); // still done
1484 	  if (res!=save)
1485 	  CERR << "unsorted" << '\n';
1486 	*/
1487 	// if (res.coord.size()==1357366)
1488 	//  CERR << "coucou" << '\n';
1489 	// if (th.dim==12){
1490 	//  CERR << "*unsigned end " << CLOCK() << '\n';
1491       }
1492       if (ans/RAND_MAX<RAND_MAX){
1493 	if (reduce.type==_INT_ && reduce.val>0){
1494 	  // Modular multiplication, convert everything to integers
1495 	  vector< T_unsigned<int,ulonglong> > p1,p2,p;
1496 	  if (convert(th,d,p1,reduce.val) && convert(other,d,p2,reduce.val)){
1497 	    if (reduce.val<46340 && 10*lagrtime<double(c1)*c2*std::log(double(giacmax(c1,c2))))
1498 	      smallmulpoly_interpolate(p1,p2,p,d,reduce.val);
1499 	    else {
1500 	      if (th.dim==1 || !threadmult(p1,p2,p,ans/d[0],reduce.val,size_t(c1c2)))
1501 		smallmult(p1,p2,p,reduce.val,size_t(c1c2)); // 46340 bound not required?
1502 	    }
1503 #if 1
1504 	    convert(p,d,res);
1505 #else
1506 	    convert_from(p,d,res,true/* threaded*/,false/*coeffapart*/);
1507 #endif
1508 	    return ;
1509 	  }
1510 	}
1511 	if ( (t1==_INT_ || t1==_ZINT) && (t2==_INT_ || t2==_ZINT)
1512 	    ){
1513 	  longlong maxp1,maxp2;
1514 	  // should be T_unsigned<long,unsigned>
1515 	  // instead tmp_operator_times converts longlong args of * to long
1516 	  vector< T_unsigned<longlong,ulonglong> > p1d,p2d,pd;
1517 	  if (debug_infolevel>1)
1518 	    CERR << CLOCK() << "longlong mult ulonglong convert begin " << CLOCK() << '\n';
1519 	  if (convert_int(th,d,p1d,maxp1) && convert_int(other,d,p2d,maxp2) ){
1520 	    double maxp1p2=double(maxp1)*maxp2;
1521 	    unsigned minc1c2=giacmin(c1,c2);
1522 	    double un63=double(ulonglong (1) << 63);
1523 	    double res_size=double(minc1c2)*maxp1p2;
1524 	    // Check number of required primes:
1525 	    res_size /= un63;
1526 	    double nprimes=std::ceil(std::log(res_size)/std::log(2147483647.));
1527 	    if (debug_infolevel>5) CERR << CLOCK() << " primes required " << nprimes << '\n';
1528 #ifdef INT128
1529 	    if (nprimes>0 && nprimes<10){
1530 	      // using multiplications with int128
1531 	      vector< T_unsigned<int128_t,ulonglong> > p1D,p2D,pD;
1532 	      convert_int128(p1d,p1D);
1533 	      convert_int128(p2d,p2D);
1534 	      if (th.dim==1 || !threadmult<int128_t,ulonglong>(p1D,p2D,pD,ans/d[0],0,c1c2))
1535 		smallmult<int128_t,ulonglong>(p1D,p2D,pD,0,c1c2);
1536 	      if (debug_infolevel>5) CERR << CLOCK() << " end int128 mult " << '\n';
1537 	      unsigned pds=pD.size();
1538 	      res_size=double(minc1c2)*maxp1p2/std::pow(2.0,127);
1539 	      if (res_size<1){
1540 		if (debug_infolevel>5) CERR << CLOCK() << " begin result conversion int 128_t ulonglong" << '\n';
1541 		convert_from<int128_t,ulonglong>(pD,d,res,true,threads>1);
1542 		if (debug_infolevel>5) CERR << CLOCK() << " end result conversion" << '\n';
1543 		return;
1544 	      }
1545 	      vector< T_unsigned<gen,ulonglong> > target;
1546 	      convert(pD,target);
1547 	      double primed=3037000499.; // floor(2^31.5)
1548 	      primed /= std::sqrt(double(giacmax(minc1c2,4)));
1549 	      gen targetprime = pow(plus_two,128);
1550 	      int prime2=prevprime(int(std::floor(primed))).val;
1551 	      for (;res_size>=1;){
1552                 if (debug_infolevel>5)
1553                   CERR << "prime used " << prime2 << '\n';
1554 		// the product of the two poly mod prime2 can be computed
1555 		// without mod computation
1556 		vector< T_unsigned<longlong,ulonglong> > p1add,p2add,add;
1557 		smod(p1d,p1add,prime2);
1558 		smod(p2d,p2add,prime2);
1559 		if (th.dim==1 || !threadmult<longlong,ulonglong>(p1add,p2add,add,ans/d[0],0,pds))
1560 		  smallmult(p1add,p2add,add,0,pds);
1561 		smod(add,add,prime2);
1562 		if (debug_infolevel>5) CERR << CLOCK() << " ichrem longlong" << '\n';
1563 		ichrem(add,prime2,pd,target,targetprime); // pd is not used at all here
1564 		res_size /= prime2;
1565 		prime2=prevprime(prime2-2).val;
1566 	      }
1567 	      if (debug_infolevel>5) CERR << CLOCK() << " begin result conversion gen ulonglong" << '\n';
1568 	      convert_from<gen,ulonglong>(target,d,res,true);
1569 	      if (debug_infolevel>5) CERR << CLOCK() << " end result conversion" << '\n';
1570 	      return;
1571 	    }
1572 #endif
1573 	    if ( res_size< 1 ){
1574 	      if (debug_infolevel>1)
1575 		CERR << CLOCK() << "longlong mult ulonglong begin " << CLOCK() << '\n';
1576 	      if (th.dim==1 || !threadmult<longlong,ulonglong>(p1d,p2d,pd,ans/d[0],0,size_t(c1c2)))
1577 		smallmult<longlong,ulonglong>(p1d,p2d,pd,0,size_t(c1c2));
1578 	      if (debug_infolevel>1)
1579 		CERR << CLOCK() << "longlong mult ulonglong end " << CLOCK() << '\n';
1580 	      convert_from<longlong,ulonglong>(pd,d,res,false);
1581 	      if (debug_infolevel>1)
1582 		CERR << CLOCK() << "longlong mult ulonglong convert end " << CLOCK() << '\n';
1583 	      return;
1584 	    }
1585 	  }
1586 	}
1587 	if (t1==_DOUBLE_ && t2==_DOUBLE_){
1588 	  vector< T_unsigned<double,ulonglong> > p1d,p2d,pd;
1589 	  if (convert_double(th,d,p1d) && convert_double(other,d,p2d) ){
1590 	    if (th.dim==1 || !threadmult<double,ulonglong>(p1d,p2d,pd,unsigned(ans/d[0]),0,size_t(c1c2)))
1591 	      smallmult<double,ulonglong>(p1d,p2d,pd,0,size_t(c1c2));
1592 	    convert_from<double,ulonglong>(pd,d,res,true);
1593 	    return;
1594 	  }
1595 	}
1596 	if (debug_infolevel>1)
1597 	  CERR << CLOCK() << "gen mult ulonglong convert begin " << CLOCK() << '\n';
1598 	vector< T_unsigned<gen,ulonglong> > p1,p2,p;
1599 	convert<gen,ulonglong>(th,d,p1);
1600 	convert<gen,ulonglong>(other,d,p2);
1601 	if (debug_infolevel>1)
1602 	  CERR << CLOCK() << "gen mult ulonglong mult begin " << CLOCK() << '\n';
1603 	smallmult<gen,ulonglong>(p1,p2,p,0,size_t(c1c2));
1604 	if (debug_infolevel>1)
1605 	  CERR << CLOCK() << "gen mult ulonglong mult end " << CLOCK() << '\n';
1606 	convert<gen,ulonglong>(p,d,res);
1607 	if (debug_infolevel>1)
1608 	  CERR << CLOCK() << "gen mult ulonglong convert end " << CLOCK() << '\n';
1609 	// if (th.dim==12)
1610 	//  CERR << "sort*longlong end " << CLOCK() << " " << res.coord.size() << '\n';
1611 	// sort(res.coord.begin(),res.coord.end(),th.m_is_strictly_greater); // still done
1612 	// if (th.dim==12)
1613 	//  CERR << "*longlong end " << CLOCK() << '\n';
1614 	return ;
1615       }
1616     } // end if c1>7 && c2>7
1617     if (debug_infolevel>1)
1618       CERR << CLOCK() << "Mul<gen> begin " << CLOCK() << '\n';
1619 #ifdef FXCG
1620     Mul_gen(ita,ita_end,itb,itb_end,res.coord,th.is_strictly_greater,th.m_is_strictly_greater);
1621 #else
1622     if (c1*c2<100)
1623       Mul_gen(ita,ita_end,itb,itb_end,res.coord,th.is_strictly_greater,th.m_is_strictly_greater);
1624     else
1625       Mul<gen>(ita,ita_end,itb,itb_end,res.coord,th.is_strictly_greater,th.m_is_strictly_greater);
1626 #endif
1627     if (debug_infolevel>1)
1628       CERR << CLOCK() << "Mul<gen> end " << CLOCK() << '\n';
1629     // if (th.dim==12)
1630     //  CERR << "* end " << CLOCK() << " " << res.coord.size() << '\n';
1631     return ;
1632 #endif // NO_TEMPLATE_MULTGCD besta_os
1633   }
1634 
operator *(const polynome & th,const polynome & other)1635   polynome operator * (const polynome & th, const polynome & other) {
1636     polynome res(th.dim,th); // reserve() is done by Mul<gen>
1637     mulpoly(th,other,res,0);
1638     return res;
1639   }
1640 
operator *=(polynome & th,const polynome & other)1641   polynome & operator *= (polynome & th, const polynome & other) {
1642 #ifdef NSPIRE
1643     th=th*other;
1644 #else
1645     mulpoly(th,other,th,0);
1646 #endif
1647     return th;
1648   }
1649 
1650   /*
1651     Note about Miller Pure Recurrence, see Knuth, TAOC v.2
1652     If   P(x) = sum_{i=0}^n p_i x^k
1653     Then   P(x)^m = sum_{k=0}^{m*n} a(m,k) x^k
1654     Where
1655       a(m,0) = p_0^m,
1656       a(m,k) = 1/(k p_0) sum_{i=1}^min(n,k) p_i ((m+1)i-k) a(m,k-i),
1657     For k<=m we have a division free implementation, let
1658     a(m,k)=b(m,k) p_0^(m-k)
1659     b(m,0)=1, b(m,k)=1/k sum_{i=1}^min(n,k) p_i ((m+1)i-k) b(m,k-i) p_0^(i-1)
1660     But for k>m, the division by p0 must be done at each step
1661     which might be too costly
1662     Example: P(x)=3x^2+2x+5, n=2
1663     m=2: P^2=9*x^4+12*x^3+34*x^2+20*x+25
1664     b(m,0)=1, a(m,0)=25
1665     b(m,1)= p_1*(3*1-1)*b(m,0)=4, a(m,1)=20
1666     b(m,2)=1/2*(p_1*(3*1-2)*b(m,1)+p_2*(3*2-2)*p_0*b(m,0))
1667           =1/2*(2*4+3*4*5)=34, a(m,2)=34
1668     a(m,3)=1/3/5*(p_1*(3*1-3)*a(m,2)+p_2*(3*2-3)*a(m,1))=12
1669     a(m,4)=1/4/5*(p_1*(3*1-4)*a(m,3)+p_2*(3*2-4)*a(m,2))=1/20*(-2*12+3*2*34)=9
1670     There is a case where no bad division occurs: if p_0 is a constant
1671     (no other variable occur) or if n==1 (binomial formula)
1672   */
powpoly(const polynome & th,int u,polynome & res)1673   bool powpoly(const polynome & th, int u,polynome & res){
1674     if (u<0){
1675 #ifndef NO_STDEXCEPT
1676       setsizeerr(gettext("Negative polynome power"));
1677 #endif
1678       return false;
1679     }
1680     if (!u){
1681       res= tensor<gen>(gen(1),th.dim);
1682       return true;
1683     }
1684     if (u==1){
1685       res=th;
1686       return true;
1687     }
1688     if (u==2){
1689       res=th*th;
1690       return true;
1691     }
1692 #ifdef TIMEOUT
1693     control_c();
1694 #endif
1695     if (ctrl_c || interrupted) {
1696       interrupted = true; ctrl_c=false;
1697       res.coord.clear();
1698       res.coord.push_back(monomial<gen>(gensizeerr(gettext("Stopped by user interruption.")),res.dim));
1699       return false;
1700     }
1701     if (th.dim==1 && u>10){
1702       modpoly a;
1703       polynome2poly1(th,1,a);
1704       gen b=pow(gen(a,_POLY1__VECT),u);
1705       if (b.type==_VECT){
1706 	poly12polynome(*b._VECTptr,1,res,1);
1707 	return true;
1708       }
1709     }
1710     vector< monomial<gen> >::const_iterator ita = th.coord.begin();
1711     vector< monomial<gen> >::const_iterator ita_end = th.coord.end();
1712     int c1=int(ita_end-ita);
1713     if (c1==0){
1714       res=th;
1715       return true;
1716     }
1717     if (c1==1){
1718       res=th;
1719       res.coord.front().value=pow(res.coord.front().value,u);
1720       res.coord.front().index = res.coord.front().index*u ;
1721       return true;
1722     }
1723     ulonglong ans=1,pid1=1;
1724     index_t d1=th.degree(),d(th.dim);
1725     for (int i=0;i<th.dim;i++){
1726       if (d1[i]==1){ // apply binomial formula
1727 	vecteur v,w(u+1);
1728 	polynome2poly1(th,i+1,v);
1729 	gen a=v[0],b=v[1],bk=b;
1730 	vecteur vbk=makevecteur(1,b);
1731 	for (int j=2;j<=u;++j){
1732 	  bk=bk*b;
1733 	  vbk.push_back(bk);
1734 	}
1735 	// (ax+b)^u=sum_j=0^u comb(u,j)*a^j*b^(u-j)*x^j
1736 	gen aj=1,cuj=1;
1737 	for (int j=0;j<=u;++j){
1738 	  w[u-j]=(aj*cuj)*vbk[u-j];
1739 	  aj=aj*a;
1740 	  cuj=(int(u-j)*cuj)/int(j+1);
1741 	}
1742 	poly12polynome(w,i+1,res,th.dim);
1743 	return true;
1744       }
1745     }
1746 #ifndef NO_TEMPLATE_MULTGCD
1747     for (int i=0;i<th.dim;++i){
1748       pid1 = pid1*unsigned(d1[i]+1);
1749     }
1750     for (int i=0;i<th.dim;++i){
1751       d[i]=d1[i]*u+1;
1752       ans = ans*unsigned(d[i]);
1753       if (ans/RAND_MAX>RAND_MAX)
1754 	break;
1755     }
1756     if (ans<=RAND_MAX){
1757       // int t1=th.coord.front().value.type;
1758       /*
1759 #ifdef HAVE_GMPXX_H
1760       if (t1<=_ZINT && mpzclass_allowed){
1761 	vector< T_unsigned<myint,unsigned> > p1,p2,p;
1762 	if (convert_myint(th,d,p1) ){
1763 	  p2=p1;
1764 	  for (int i=1;i<u;++i){
1765 	    if (debug_infolevel>20)
1766 	    CERR << "power mpz " << i << " " << CLOCK() << '\n';
1767 	    unsigned c1c2 = p1.size()*p2.size();
1768 	    if (th.dim==1 || !threadmult<myint,unsigned>(p1,p2,p,ans/d[0],0,c1c2))
1769 	      smallmult<myint,unsigned>(p1,p2,p,0,c1c2);
1770 	    p1=p;
1771 	  }
1772 	  convert_from<myint,unsigned>(p,d,res,false);
1773 	  return;
1774 	}
1775       }
1776 #endif
1777       */
1778       vector< T_unsigned<gen,unsigned> > p1,p2,p;
1779       convert<gen,unsigned>(th,d,p1);
1780       p2=p1;
1781       for (int i=1;i<u;++i){
1782 	if (debug_infolevel>20)
1783 	  CERR << "power gen " << i << " " << CLOCK() << '\n';
1784 	unsigned c1c2 = unsigned(p1.size()*p2.size());
1785 	// threadmult<gen,.> does not work on multi-CPU (malloc error with GMP data structures)
1786 	// if (th.dim==1 || !threadmult<gen,unsigned>(p1,p2,p,ans/d[0],0,c1c2))
1787 	  smallmult<gen,unsigned>(p1,p2,p,0,c1c2);
1788 	p1=p;
1789       }
1790       convert<gen,unsigned>(p,d,res);
1791     }
1792     else // ans>RAND_MAX
1793 #endif // NO_TEMPLATE_MULTGCD
1794       res=Tpow(th,u);
1795     return true;
1796   }
1797 
operator -(const polynome & th)1798   polynome operator - (const polynome & th) {
1799     // Tensor addition
1800     polynome res(th.dim,th);
1801     vector< monomial<gen> >::const_iterator a = th.coord.begin();
1802     vector< monomial<gen> >::const_iterator a_end = th.coord.end();
1803     res.coord.reserve(a_end - a );
1804     for (;a!=a_end;++a){
1805       res.coord.push_back(monomial<gen>(-(*a).value,(*a).index));
1806     }
1807     return res;
1808   }
1809 
submulpoly(const polynome & a,const polynome & b,const polynome & q,polynome & r)1810   void submulpoly(const polynome & a,const polynome & b,const polynome & q,polynome & r){
1811 #if 0
1812     r=a-b*q;
1813 #else
1814     polynome tmp(a.dim);
1815     mulpoly(b,q,tmp,0);
1816     vector< monomial<gen> >::const_iterator a_beg=a.coord.begin();
1817     vector< monomial<gen> >::const_iterator a_end=a.coord.end();
1818     vector< monomial<gen> >::const_iterator b_beg=tmp.coord.begin();
1819     vector< monomial<gen> >::const_iterator b_end=tmp.coord.end();
1820     vector< monomial<gen> > & new_coord=r.coord;
1821     new_coord.clear();
1822     for (;;) {
1823       // If a is empty, fill up with elements from b and stop
1824       if (a_beg == a_end) {
1825 	while (b_beg != b_end) {
1826 	  new_coord.push_back(-(*b_beg));
1827 	  ++b_beg;
1828 	}
1829 	break;
1830       }
1831       const index_m & pow_a = a_beg->index;
1832       // If b is empty, fill up with elements from a and stop
1833       if (b_beg == b_end) {
1834 	while (a_beg != a_end) {
1835 	  new_coord.push_back(*a_beg);
1836 	  ++a_beg;
1837 	}
1838 	break;
1839       }
1840       const index_m & pow_b = b_beg->index;
1841       // a and b are non-empty, compare powers
1842       if (pow_a!=pow_b){
1843 	if (a.is_strictly_greater(pow_a, pow_b)) {
1844 	  // a has lesser power, get coefficient from a
1845 	  new_coord.push_back(*a_beg);
1846 	  ++a_beg;
1847 	}
1848 	else  {
1849 	  // b has lesser power, get coefficient from b
1850 	  new_coord.push_back(-(*b_beg));
1851 	  ++b_beg;
1852 	}
1853       }
1854       else {
1855 	gen diff = (*a_beg).value - (*b_beg).value;
1856 	if (!is_zero(diff))
1857 	  new_coord.push_back(monomial<gen>(diff,pow_a));
1858 	++a_beg;
1859 	++b_beg;
1860       }
1861     }
1862 #endif
1863   }
1864 
1865   // exactquo==2 means we know that b divides a and we search the cofactor
1866   // exactquo==1 means we want to check that b divides a
1867   // exactquo==-1 means compute quotient first using heap div then r=a-b*quo
1868   // exactquo==-2 means compute quotient only using heap div
divrem1(const polynome & a,const polynome & b,polynome & quo,polynome & r,int exactquo,bool allowrational)1869   bool divrem1(const polynome & a,const polynome & b,polynome & quo,polynome & r,int exactquo,bool allowrational) {
1870     quo.coord.clear();
1871     quo.dim=a.dim;
1872     r.dim=a.dim;
1873     r.coord.clear();
1874     int bs=int(b.coord.size());
1875     if ( b.dim<=1 || bs==1 || a.coord.empty() ){
1876       return a.TDivRem(b,quo,r,allowrational) && (exactquo>0?r.coord.empty():true) ;
1877     }
1878     int bdeg=b.coord.front().index.front(),rdeg=a.lexsorted_degree(),ddeg=rdeg-bdeg;
1879 #ifndef NO_TEMPLATE_MULTGCD
1880     int hashdivremres=0;
1881     if (ddeg>3 && !allowrational){
1882       index_t d1=a.degree(),d2=b.degree(),d3=b.coord.front().index.iref(),d(a.dim);
1883       // i-th degrees of th / other in quotient and remainder
1884       // are <= i-th degree of th + ddeg*(i-th degree of other - i-th degree of lcoeff of other)
1885       double ans=1;
1886       for (int i=0;i<a.dim;++i){
1887 	if (exactquo==2)
1888 	  d[i]=d1[i]+1;
1889 	else
1890 	  d[i]=d1[i]+(ddeg+1)*(d2[i]-d3[i])+1;
1891 	int j=1;
1892 	// round to newt power of 2
1893 	for (;;j++){
1894 	  if (!(d[i] >>= 1))
1895 	    break;
1896 	}
1897 	d[i] = 1 << j;
1898 	ans = ans*unsigned(d[i]);
1899 	if (ans/RAND_MAX>RAND_MAX)
1900 	  break;
1901       }
1902       bool doit=true;
1903       if (ans<RAND_MAX){
1904 	std::vector<unsigned> vars(a.dim);
1905 	vars[a.dim-1]=1;
1906 	for (int i=a.dim-2;i>=0;--i){
1907 	  vars[i]=d[i+1]*vars[i+1];
1908 	}
1909 	if (debug_infolevel>1)
1910 	  CERR << "divrem1 convert " << CLOCK() << '\n';
1911 	if (a.coord.front().value.type==_MOD || b.coord.front().value.type==_MOD){
1912 	  gen reduce=a.coord.front().value.type==_MOD?*(a.coord.front().value._MODptr+1):*(b.coord.front().value._MODptr+1);
1913 	  if (reduce.type==_INT_){
1914 	    polynome thm,otherm;
1915 	    unmodularize(a,thm);
1916 	    unmodularize(b,otherm);
1917 	    vector< T_unsigned<int,unsigned> > p1,p2,p,quot32,remain32;
1918 	    if (convert(thm,d,p1,reduce.val) && convert(otherm,d,p2,reduce.val)){
1919 	      if (hashdivrem<int,unsigned>(p1,p2,quot32,remain32,vars,reduce.val,0,false,exactquo)>=1){
1920 		convert_from(quot32,d,quo,true);
1921 		if (exactquo==-1 && hashdivremres==2)
1922 		  submulpoly(a,b,quo,r);
1923 		else
1924 		  convert_from(remain32,d,r,true);
1925 		int32_modularize(quo,reduce);
1926 		int32_modularize(r,reduce);
1927 		return true;
1928 	      }
1929 	    }
1930 	  }
1931 	}
1932 	else {
1933 	  std::vector< T_unsigned<longlong,unsigned> > p1,p2,quot,remain;
1934 	  longlong maxp1,maxp2;
1935 	  doit=convert_int(a,d,p1,maxp1) && convert_int(b,d,p2,maxp2) && maxp1/RAND_MAX < RAND_MAX;
1936 	  if (doit){
1937 	    if (maxp1<int(RAND_MAX) && maxp2<double(RAND_MAX)/p2.size()){
1938 	      if (debug_infolevel>1)
1939 		CERR << "hashdivrem1 int32 begin " << CLOCK() << " maxp1=" << maxp1 << " maxp2=" << maxp2 << " ddeg=" << ddeg << '\n';
1940 	      // try with int instead of longlong
1941 	      std::vector< T_unsigned<int,unsigned> > p132,p232,quot32,remain32;
1942 	      if (convert_int32(a,d,p132) && convert_int32(b,d,p232) &&
1943 		  (hashdivremres=hashdivrem<int,unsigned>(p132,p232,quot32,remain32,vars,0,RAND_MAX/double(maxp2)/p2.size(),false,exactquo))>=1){
1944 		if (debug_infolevel>1)
1945 		  CERR << "hashdivrem1 int32 success " << CLOCK() << " maxp1=" << maxp1 << " maxp2=" << maxp2 << " ddeg=" << ddeg << '\n';
1946 		convert_from(quot32,d,quo,true);
1947 		if (exactquo==-1 && hashdivremres==2) submulpoly(a,b,quo,r); else
1948 		  convert_from(remain32,d,r,true);
1949 		return true;
1950 	      }
1951 	      else {
1952 		if (debug_infolevel>1)
1953 		  CERR << "hashdivrem1 int32 failure " << CLOCK() << '\n';
1954 	      }
1955 	    }
1956 	    if (debug_infolevel>1)
1957 	      CERR << "hashdivrem1 longlong begin " << CLOCK() << " maxp1=" << maxp1 << " maxp2=" << maxp2 << " ddeg=" << ddeg << '\n';
1958 	    if ((hashdivremres=hashdivrem<longlong,unsigned>(p1,p2,quot,remain,vars,/* reduce*/0,RAND_MAX/double(maxp2)/p2.size()*RAND_MAX,false,exactquo))>=1){
1959 	      if (debug_infolevel>1)
1960 		CERR << "hashdivrem1 longlong end " << CLOCK() << '\n';
1961 	      convert_from(quot,d,quo,false);
1962 	      if (hashdivremres==2 && exactquo==-1) submulpoly(a,b,quo,r); else
1963 		convert_from(remain,d,r,false);
1964 	      return true;
1965 	    }
1966 	    else {
1967 	      if (debug_infolevel>1)
1968 		CERR << "hashdivrem1 longlong failure " << CLOCK() << '\n';
1969 	    }
1970 	  }
1971 #ifdef INT128
1972 	  {
1973 	    int128_t maxp1,maxp2;
1974 	    vector< T_unsigned<int128_t,unsigned> > aD,bD,qD,rD;
1975 	    if (debug_infolevel>1)
1976 	      CERR << "hashdivrem1 int128 int begin " << CLOCK()  << " ddeg=" << ddeg << '\n';
1977 	    if (convert_int(a,d,aD,maxp1) && convert_int(b,d,bD,maxp2) && (hashdivremres=hashdivrem<int128_t,unsigned>(aD,bD,qD,rD,vars,0,1.7e38/double(maxp2)/p2.size(),false,exactquo))>=1){
1978 	      if (debug_infolevel>1)
1979 		CERR << "hashdivrem1 int128 int success " << CLOCK() << " maxp1=" << double(maxp1) << " maxp2=" << double(maxp2) << " ddeg=" << ddeg << '\n';
1980 	      convert_from<int128_t,unsigned>(qD,d,quo,true);
1981 	      if (hashdivremres==2 && exactquo==-1) submulpoly(a,b,quo,r); else
1982 		convert_from<int128_t,unsigned>(rD,d,r,true);
1983 	      return true;
1984 	    }
1985 	  }
1986 #endif
1987 	  doit=false;
1988 	}
1989 #ifdef HAVE_GMPXX_H
1990 	if (mpzclass_allowed)
1991 	{
1992 	  std::vector< T_unsigned<myint,unsigned> > p1,p2,quot,remain;
1993 	  if (debug_infolevel>1)
1994 	    CERR << "divrem1mpz int convert " << CLOCK() << '\n';
1995 	  doit=convert_myint(a,d,p1) && convert_myint(b,d,p2);
1996 	  if (doit){
1997 	    if (debug_infolevel>1)
1998 	      CERR << "hashdivrem1mpz int begin " << CLOCK() << " ddeg=" << ddeg << '\n';
1999 	    if ((hashdivremres=hashdivrem<myint,unsigned>(p1,p2,quot,remain,vars,/* reduce */ 0,/* no size check */0.0,false,exactquo))>=1){
2000 	      if (debug_infolevel>1)
2001 		CERR << "hashdivrem1mpz int end " << CLOCK() << '\n';
2002 	      convert_from(quot,d,quo,false);
2003 	      if (hashdivremres==2 && exactquo==-1) submulpoly(a,b,quo,r); else
2004 		convert_from(remain,d,r,false);
2005 	      return true;
2006 	    }
2007 	    else {
2008 	      if (debug_infolevel>1)
2009 		CERR << "hashdivrem1mpz int failure " << CLOCK() << '\n';
2010 	    }
2011 	  }
2012 	}
2013 #endif
2014       }
2015       if (doit && ans/RAND_MAX<RAND_MAX){
2016 	//#ifdef __VISUALC__ // Visual C++?
2017 	// typedef unsigned __int64 ulonglong ;
2018 	// #else
2019 	// typedef unsigned long long ulonglong;
2020 	//#endif
2021 	std::vector<ulonglong> vars(a.dim);
2022 	vars[a.dim-1]=1;
2023 	for (int i=a.dim-2;i>=0;--i){
2024 	  vars[i]=d[i+1]*vars[i+1];
2025 	}
2026 	if (debug_infolevel>1)
2027 	  CERR << "divrem1 convert " << CLOCK() << '\n';
2028 	if (a.coord.front().value.type==_MOD || b.coord.front().value.type==_MOD){
2029 	  gen reduce=a.coord.front().value.type==_MOD?*(a.coord.front().value._MODptr+1):*(b.coord.front().value._MODptr+1);
2030 	  if (reduce.type==_INT_){
2031 	    polynome thm,otherm;
2032 	    unmodularize(a,thm);
2033 	    unmodularize(b,otherm);
2034 	    vector< T_unsigned<int,ulonglong> > p1,p2,p,quot32,remain32;
2035 	    if (convert(thm,d,p1,reduce.val) && convert(otherm,d,p2,reduce.val)){
2036 	      if (hashdivrem<int,ulonglong>(p1,p2,quot32,remain32,vars,reduce.val,0,false,exactquo)>=1){
2037 		convert_from(quot32,d,quo,true);
2038 		if (exactquo==-1 && hashdivremres==2)
2039 		  submulpoly(a,b,quo,r);
2040 		else
2041 		  convert_from(remain32,d,r,true);
2042 		int32_modularize(quo,reduce);
2043 		int32_modularize(r,reduce);
2044 		return true;
2045 	      }
2046 	    }
2047 	  }
2048 	}
2049 	else {
2050 	  std::vector< T_unsigned<longlong,ulonglong> > p1,p2,quot,remain;
2051 	  longlong maxp1,maxp2;
2052 	  doit=convert_int(a,d,p1,maxp1) && convert_int(b,d,p2,maxp2) && maxp1/RAND_MAX < RAND_MAX;
2053 	  // doit=false;
2054 	  if (doit){
2055 	    if (debug_infolevel>1)
2056 	      CERR << "hashdivrem1 longlong ulonglong begin " << CLOCK() << " maxp1=" << maxp1 << " maxp2=" << maxp2 << " ddeg=" << ddeg << '\n';
2057 	    if ((hashdivremres=hashdivrem<longlong,ulonglong>(p1,p2,quot,remain,vars,/* reduce */0,RAND_MAX/double(maxp2)/p2.size()*RAND_MAX,false,exactquo))>=1){
2058 	      if (debug_infolevel>1)
2059 		CERR << "hashdivrem1 longlong ulonglong end " << CLOCK() << '\n';
2060 	      convert_from(quot,d,quo,false);
2061 	      if (hashdivremres==2 && exactquo==-1) submulpoly(a,b,quo,r); else
2062 		convert_from(remain,d,r,false);
2063 	      return true;
2064 	    }
2065 	    else {
2066 	      if (debug_infolevel>1)
2067 		CERR << "hashdivrem1 longlong ulonglong failure " << CLOCK() << '\n';
2068 	    }
2069 	  }
2070 #ifdef INT128
2071 	  {
2072 	    int128_t maxp1,maxp2;
2073 	    vector< T_unsigned<int128_t,ulonglong> > aD,bD,qD,rD;
2074 	    if (debug_infolevel>1)
2075 	      CERR << "hashdivrem1 int128 ulonglong begin " << CLOCK() <<  " ddeg=" << ddeg << '\n';
2076 	    if (convert_int(a,d,aD,maxp1) && convert_int(b,d,bD,maxp2) && (hashdivremres=hashdivrem<int128_t,ulonglong>(aD,bD,qD,rD,vars,0,1.7e38/double(maxp2)/p2.size(),false,exactquo))>=1){
2077 	      if (debug_infolevel>1)
2078 		CERR << "hashdivrem1 int128 ulonglong success " << CLOCK() << " maxp1=" << double(maxp1) << " maxp2=" << double(maxp2) << " ddeg=" << ddeg << '\n';
2079 	      convert_from<int128_t,ulonglong>(qD,d,quo,true);
2080 	      if (hashdivremres==2 && exactquo==-1) submulpoly(a,b,quo,r); else
2081 		convert_from<int128_t,ulonglong>(rD,d,r,true);
2082 	      return true;
2083 	    }
2084 	  }
2085 #endif
2086 	}
2087 #ifdef HAVE_GMPXX_H
2088 	if (mpzclass_allowed)
2089 	{
2090 	  std::vector< T_unsigned<myint,ulonglong> > p1,p2,quot,remain;
2091 	  // longlong maxp1,maxp2;
2092 	  if (debug_infolevel>1)
2093 	    CERR << "divrem1mpz ulonglong convert " << CLOCK() << '\n';
2094 	  doit=convert_myint(a,d,p1) && convert_myint(b,d,p2);
2095 	  if (doit){
2096 	    if (debug_infolevel>1)
2097 	      CERR << "hashdivrem1z ulonglong begin " << CLOCK() <<  " ddeg=" << ddeg << '\n';
2098 	    if ((hashdivremres=hashdivrem<myint,ulonglong>(p1,p2,quot,remain,vars,/* reduce */ 0,/* no size check */0.0,false,exactquo))>=1){
2099 	      if (debug_infolevel>1)
2100 		CERR << "hashdivrem1 ulonglong end " << CLOCK() << '\n';
2101 	      convert_from(quot,d,quo,false);
2102 	      if (hashdivremres==2 && exactquo==-1) submulpoly(a,b,quo,r); else
2103 		convert_from(remain,d,r,false);
2104 	      return true;
2105 	    }
2106 	    else {
2107 	      if (debug_infolevel>1)
2108 		CERR << "hashdivrem1 ulonglong failure " << CLOCK() << '\n';
2109 	    }
2110 	  }
2111 	}
2112 #endif
2113       }
2114     } // end if (ddeg>3)
2115 #endif // NO_TEMPLATE_MULTGCD
2116     return a.TDivRem1(b,quo,r,allowrational,exactquo>0);
2117   }
2118 
operator /(const polynome & th,const polynome & other)2119   polynome operator / (const polynome & th,const polynome & other) {
2120     if (Tis_one(other)) return th;
2121     polynome rem(th.dim,th),quo(th.dim,th);
2122     // if ( !(th).TDivRem1(other,quo,rem) )
2123     if ( !divrem1(th,other,quo,rem) ){
2124 #ifdef NO_STDEXCEPT
2125       quo.coord.clear();
2126       quo.coord.push_back(monomial<gen>(gensizeerr(gettext("Unable to divide, perhaps due to rounding error")+th.print()+" / "+other.print()),quo.dim));
2127 #else
2128       setsizeerr(gettext("Unable to divide, perhaps due to rounding error")+th.print()+" / "+other.print());
2129 #endif
2130     }
2131     return(quo);
2132   }
2133 
operator /(const polynome & th,const gen & fact)2134   polynome operator / (const polynome & th,const gen & fact ) {
2135     if (fact==gen(1))
2136       return th;
2137     polynome res(th.dim,th);
2138     vector< monomial<gen> >::const_iterator a = th.coord.begin();
2139     vector< monomial<gen> >::const_iterator a_end = th.coord.end();
2140     Div(a,a_end,fact,res.coord);
2141     return res;
2142   }
2143 
operator %(const polynome & th,const polynome & other)2144   polynome operator % (const polynome & th,const polynome & other) {
2145     polynome rem(th.dim,th),quo(th.dim,th);
2146     if ( !(th).TDivRem1(other,quo,rem) ){
2147 #ifdef NO_STDEXCEPT
2148       rem.coord.clear();
2149       rem.coord.push_back(monomial<gen>(gensizeerr(gettext("Unable to divide, perhaps due to rounding error")+th.print()+" / "+other.print()),quo.dim));
2150 #else
2151       setsizeerr(gettext("Unable to divide, perhaps due to rounding error")+th.print()+" / "+other.print());
2152 #endif
2153     }
2154     return(rem);
2155   }
2156 
operator %(const polynome & th,const gen & modulo)2157   polynome operator % (const polynome & th, const gen & modulo) {
2158     polynome res(th.dim,th);
2159     vector< monomial<gen> >::const_iterator a = th.coord.begin();
2160     vector< monomial<gen> >::const_iterator a_end = th.coord.end();
2161     res.coord.reserve(a_end - a );
2162     for (;a!=a_end;++a){
2163       gen tmp((*a).value % modulo);
2164       if (!is_zero(tmp))
2165 	res.coord.push_back(monomial<gen>(tmp,a->index));
2166     }
2167     return res;
2168   }
2169 
re(const polynome & th)2170   polynome re(const polynome & th){
2171     return Tapply(th,no_context_re);
2172   }
2173 
im(const polynome & th)2174   polynome im(const polynome & th){
2175     return Tapply(th,no_context_im);
2176   }
2177 
conj(const polynome & th)2178   polynome conj(const polynome & th){
2179     return Tapply(th,no_context_conj);
2180   }
2181 
smod(const polynome & th,const gen & modulo,polynome & res)2182   void smod(const polynome & th, const gen & modulo,polynome & res){
2183     vector< monomial<gen> >::const_iterator a = th.coord.begin();
2184     vector< monomial<gen> >::const_iterator a_end = th.coord.end();
2185     res.coord.clear();
2186     res.coord.reserve(a_end - a );
2187     for (;a!=a_end;++a){
2188       const gen & tmp=smod(a->value, modulo);
2189       if (!is_zero(tmp))
2190 	res.coord.push_back(monomial<gen>(tmp,a->index));
2191     }
2192   }
2193 
smod(const polynome & th,const gen & modulo)2194   polynome smod(const polynome & th, const gen & modulo) {
2195     polynome res(th.dim,th);
2196     smod(th,modulo,res);
2197     return res;
2198   }
2199 
2200   // var is the variable number to extract, from 1 to p.dim
polynome2poly1(const polynome & pp,int var,vecteur & v)2201   void polynome2poly1(const polynome & pp,int var,vecteur & v){
2202     if (pp.dim==0){
2203       gensizeerr("polynome2poly1");
2204       v.clear();
2205       if (!pp.coord.empty())
2206 	v.push_back(pp.coord.front().value);
2207     }
2208     if (var!=1){
2209       polynome p(pp);
2210       p.reorder(transposition(0,var-1,p.dim));
2211       polynome2poly1(p,1,v);
2212       return;
2213     }
2214     v.clear();
2215     int current_deg=pp.lexsorted_degree();
2216     v.reserve(current_deg+1);
2217     vector< monomial<gen> >::const_iterator it=pp.coord.begin(),itend=pp.coord.end();
2218     for (;it!=itend;--current_deg){
2219       if (it->index.front()==current_deg){
2220 	if (pp.dim==1){
2221 	  v.push_back(it->value);
2222 	  ++it;
2223 	}
2224 	else
2225 	  v.push_back(Tnextcoeff<gen>(it,itend));
2226       }
2227       else {
2228 #if 0
2229 	if (pp.dim==1)
2230 	  v.push_back(0);
2231 	else
2232 	  v.push_back(polynome(pp.dim-1));
2233 #else
2234 	  v.push_back(0);
2235 #endif
2236       }
2237     }
2238     for (;current_deg>=0;--current_deg)
2239       v.push_back(zero);
2240   }
2241 
polynome2poly1(const polynome & p,int var)2242   vecteur polynome2poly1(const polynome & p,int var){
2243     vecteur v;
2244     polynome2poly1(p,var,v);
2245     return v;
2246   }
2247 
2248   // like polynome2poly1 for univariate p
polynome12poly1(const polynome & p)2249   vecteur polynome12poly1(const polynome & p){
2250     if (p.dim>1)
2251       return polynome2poly1(p,1);
2252     int current_deg=p.lexsorted_degree();
2253     vecteur v;
2254     v.reserve(current_deg+1);
2255     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
2256     for (;it!=itend;--current_deg){
2257       if (it->index.front()==current_deg){
2258 	v.push_back(it->value);
2259 	++it;
2260       }
2261       else
2262 	v.push_back(zero);
2263     }
2264     for (;current_deg>=0;--current_deg)
2265       v.push_back(zero);
2266     return v;
2267   }
2268 
polynome2poly1(const polynome & p)2269   vecteur polynome2poly1(const polynome & p){
2270     if (p.dim>1)
2271       return polynome2poly1(p,1);
2272     vecteur v;
2273     int current_deg=p.lexsorted_degree();
2274     v.reserve(current_deg+1);
2275     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
2276     for (;it!=itend;--current_deg){
2277       if (it->index.front()==current_deg){
2278 	v.push_back(it->value);
2279 	++it;
2280       }
2281       else
2282 	v.push_back(zero);
2283     }
2284     for (;current_deg>=0;--current_deg)
2285       v.push_back(zero);
2286     return v;
2287   }
2288 
polynome2poly1(const gen & e,int var)2289   gen polynome2poly1(const gen & e,int var){
2290       if (e.type==_POLY)
2291           return polynome2poly1(*e._POLYptr,var);
2292       if (e.type!=_FRAC)
2293           return e;
2294       return fraction(polynome2poly1(e._FRACptr->num,var),polynome2poly1(e._FRACptr->den,var));
2295   }
2296 
inner_POLYdim(const vecteur & v)2297   int inner_POLYdim(const vecteur & v){
2298     const_iterateur it=v.begin(),itend=v.end();
2299     int dim=1;
2300     for (;it!=itend;++it){
2301       if (it->type==_POLY){
2302 	dim=it->_POLYptr->dim+1;
2303 	break;
2304       }
2305     }
2306     return dim;
2307   }
2308 
untrunc(const gen & e,int degree,int dimension)2309   gen untrunc(const gen & e,int degree,int dimension){
2310     if (e.type==_POLY)
2311       return e._POLYptr->untrunc(degree,dimension);
2312     if (e.type==_EXT)
2313       return algebraic_EXTension(untrunc(*e._EXTptr,degree,dimension),untrunc(*(e._EXTptr+1),degree,dimension));
2314     if (e.type==_VECT){
2315       const_iterateur it=e._VECTptr->begin(),itend=e._VECTptr->end();
2316       vecteur res;
2317       res.reserve(itend-it);
2318       for (;it!=itend;++it)
2319 	res.push_back(untrunc(*it,degree,dimension));
2320       return res;
2321     }
2322     if (e.type==_FRAC)
2323       return fraction(untrunc(e._FRACptr->num,degree,dimension),untrunc(e._FRACptr->den,0,dimension));
2324     return tensor<gen>(monomial<gen>(e,degree,1,dimension));
2325   }
2326 
vecteur2polynome(const vecteur & v,int dimension)2327   gen vecteur2polynome(const vecteur & v,int dimension){
2328     const_iterateur it=v.begin(),itend=v.end();
2329     gen e;
2330     for (int d=int(itend-it)-1;it!=itend;++it,--d){
2331       if (!is_zero(*it))
2332 	e = e+untrunc(*it,d,dimension);
2333     }
2334     return e;
2335   }
2336 
poly12polynome(const vecteur & v)2337   polynome poly12polynome(const vecteur & v){
2338     const_iterateur it=v.begin(),itend=v.end();
2339     polynome p(1);
2340     for (int d=int(itend-it)-1;it!=itend;++it,--d){
2341       if (!is_zero(*it))
2342 	p.coord.push_back(monomial<gen>(*it,d,1,1));
2343     }
2344     return p;
2345   }
2346 
2347   // WARNING: var begins at 1 and ends at dimension
poly12polynome(const vecteur & v,int var,polynome & p,int dimension)2348   void poly12polynome(const vecteur & v, int var,polynome & p,int dimension){
2349     if (dimension)
2350       p.dim=dimension;
2351     else
2352       p.dim=inner_POLYdim(v);
2353     p.coord.clear();
2354     const_iterateur it=v.begin(),itend=v.end();
2355     for (int d=int(itend-it)-1;it!=itend;++it,--d){
2356       if (is_zero(*it))
2357 	continue;
2358       if (it->type!=_POLY || (it->_POLYptr->dim+1)!=p.dim)
2359 	p.coord.push_back(monomial<gen>(*it,d,1,p.dim));
2360       else {
2361 	vector< monomial<gen> >::const_iterator p_it=it->_POLYptr->coord.begin(),p_itend=it->_POLYptr->coord.end();
2362 	for (;p_it!=p_itend;++p_it)
2363 	  p.coord.push_back(p_it->untrunc(d,p.dim));
2364       }
2365     }
2366     if (var!=1){
2367       p.reorder(transposition(0,var-1,p.dim));
2368     }
2369   }
2370 
poly1_2_polynome(const vecteur & v,int dimension)2371   polynome poly1_2_polynome(const vecteur & v, int dimension){
2372     polynome p(dimension);
2373     const_iterateur it=v.begin(),itend=v.end();
2374     for (int d=int(itend-it)-1;it!=itend;++it,--d){
2375       if (is_zero(*it))
2376 	continue;
2377       p.coord.push_back(monomial<gen>(*it,d,1,p.dim));
2378     }
2379     return p;
2380   }
2381 
poly12polynome(const vecteur & v,int var,int dimension)2382   polynome poly12polynome(const vecteur & v,int var,int dimension){
2383     polynome p(0);
2384     poly12polynome(v,var,p,dimension);
2385     return p;
2386   }
2387 
2388   // assuming pmod and qmod are prime together, find r such that
2389   // r = p mod pmod  and r = q mod qmod
2390   // hence r = p + A*pmod = q + B*qmod
2391   // or A*pmod -B*qmod = q - p
2392   // assuming u*pmod+v*pmod=d we get
2393   // A=u*(q-p)/d
ichinrem(const polynome & p,const polynome & q,const gen & pmod,const gen & qmod)2394   polynome ichinrem(const polynome &p,const polynome & q,const gen & pmod,const gen & qmod){
2395     gen u,v,d,tmp,pqmod(pmod*qmod);
2396     egcd(pmod,qmod,u,v,d);
2397     // COUT << u << "*" << pmod << "+" << v << "*" << qmod << "=" << d << " " << u*pmod+v*qmod << '\n';
2398     vector< monomial<gen> >::const_iterator a = p.coord.begin();
2399     vector< monomial<gen> >::const_iterator a_end = p.coord.end();
2400     vector< monomial<gen> >::const_iterator b = q.coord.begin();
2401     vector< monomial<gen> >::const_iterator b_end = q.coord.end();
2402     polynome res(p.dim);
2403     res.coord.reserve(a_end - a );
2404     for (;(a!=a_end)&&(b!=b_end);){
2405       if (a->index != b->index){
2406 	if (a->index>=b->index){
2407 	  tmp=a->value-rdiv(u*a->value,d,context0);
2408 	  res.coord.push_back(monomial<gen>(smod(tmp,pqmod),a->index));
2409 	  ++a;
2410 	}
2411 	else {
2412 	  tmp=rdiv(u*b->value,d,context0);
2413 	  res.coord.push_back(monomial<gen>(smod(tmp,pqmod),b->index));
2414 	  ++b;
2415 	}
2416       }
2417       else {
2418 	tmp=a->value+rdiv(u*(b->value-a->value),d,context0) *pmod ;
2419 	// COUT << a->value << " " << b->value << "->" << tmp << " " << pqmod << '\n';
2420 	res.coord.push_back(monomial<gen>(smod(tmp,pqmod),b->index));
2421 	++b;
2422 	++a;
2423       }
2424     }
2425     for (;a!=a_end;++a)
2426       res.coord.push_back(monomial<gen>(smod(a->value-rdiv(u*(a->value),d,context0),pqmod),a->index));
2427     for (;b!=b_end;++b)
2428       res.coord.push_back(monomial<gen>(smod(rdiv(u*b->value,d,context0),pqmod),b->index));
2429     return res;
2430   }
2431 
divrem(const polynome & th,const polynome & other,polynome & quo,polynome & rem,bool allowrational)2432   bool divrem (const polynome & th, const polynome & other, polynome & quo, polynome & rem, bool allowrational ){
2433     return th.TDivRem(other,quo,rem,allowrational);
2434   }
2435 
exactquotient(const polynome & a,const polynome & b,polynome & quo,bool allowrational)2436   bool exactquotient(const polynome & a,const polynome & b,polynome & quo,bool allowrational){
2437     CLOCK_T beg=CLOCK(),delta;
2438     if (debug_infolevel>1)
2439       CERR << beg*1e-6 << " exactquo begin" << '\n';
2440     bool res= a.Texactquotient(b,quo,allowrational);
2441     delta=CLOCK()-beg;
2442     if (delta && debug_infolevel>1) // a.dim>=inspectdim
2443       CERR << "exactquo end " << delta*1e-6 << " " << res << '\n';
2444     return res;
2445   }
2446 
divremmod2(const polynome & th,const polynome & other,const gen & modulo,polynome & quo,polynome & rem)2447   static bool divremmod2 (const polynome & th,const polynome & other, const gen & modulo,polynome & quo, polynome & rem) {
2448     int asize=int(th.coord.size());
2449     if (!asize){
2450       quo=th;
2451       rem=th;
2452       return true;
2453     }
2454     int bsize=int(other.coord.size());
2455     if (bsize==0){
2456 #ifndef NO_STDEXCEPT
2457       setsizeerr(gettext("gausspol.cc/divremmod2"));
2458 #endif
2459       return false;
2460     }
2461     index_m a_max = th.coord.front().index;
2462     index_m b_max = other.coord.front().index;
2463     quo.coord.clear();
2464     quo.dim=th.dim;
2465     rem.dim=th.dim;
2466     if ( (bsize==1) && (b_max==b_max*0) ){
2467       rem.coord.clear();
2468       gen b=other.coord.front().value;
2469       if (b==gen(1))
2470 	quo = th ;
2471       else {
2472 	b=invmod(b,modulo);
2473 	vector< monomial<gen> >::const_iterator itend=th.coord.end();
2474 	for (vector< monomial<gen> >::const_iterator it=th.coord.begin();it!=itend;++it)
2475 	  quo.coord.push_back(monomial<gen>( smod(it->value*b,modulo),it->index));
2476       }
2477     return true;
2478     }
2479     rem=th;
2480     if ( ! (a_max>=b_max) ){
2481       // test that the first power of a_max is < to that of b_max
2482       return (a_max.front()<b_max.front());
2483     }
2484     // bool mult=is_cinteger(other.coord.front().value);
2485     gen b=invmod(other.coord.front().value,modulo);
2486     while (a_max >= b_max){
2487       gen q=smod(rem.coord.front().value*b, modulo);
2488       quo.coord.push_back(monomial<gen>(q,a_max-b_max));
2489       polynome temp=other.shift(a_max-b_max,q);
2490       rem = smod(rem-temp, modulo);
2491       if (rem.coord.size())
2492 	a_max=rem.coord.front().index;
2493       else
2494 	break;
2495     }
2496     return(true);
2497   }
2498 
divremmod(const polynome & th,const polynome & other,const gen & modulo,polynome & quo,polynome & r)2499   bool divremmod (const polynome & th,const polynome & other, const gen & modulo,polynome & quo, polynome & r) {
2500     quo.coord.clear();
2501     quo.dim=th.dim;
2502     r.dim=th.dim;
2503     if ( (th.dim<=1) || (th.coord.empty()) )
2504       return divremmod2(th,other,modulo,quo,r);
2505     int os=int(other.coord.size());
2506     if (!os){
2507       r=th;
2508       return true;
2509     }
2510     if (os==1){
2511       // Check for a division by 1
2512       if (is_one(other.coord.front().value) && other.coord.front().index.is_zero()){
2513 	quo=th;
2514 	r.coord.clear();
2515 	return true;
2516       }
2517       // IMPROVE Invert other.coord.front() and shift/multiply
2518 
2519     }
2520     std::vector< monomial<gen> >::const_iterator it=other.coord.begin();
2521     int bdeg=it->index.front(),rdeg=th.lexsorted_degree(),ddeg=rdeg-bdeg;
2522 #ifndef NO_TEMPLATE_MULTGCD
2523     // FIXME hashdivrem may fail if not divisible if false is commented below
2524     // search new quotient term in threaded.h if heap multiplication is used
2525     if (//false &&
2526 	ddeg>2 && os>10
2527 	){
2528       index_t d1=th.degree(),d2=other.degree(),d3=other.coord.front().index.iref(),d(th.dim);
2529       // i-th degrees of th / other in quotient and remainder
2530       // are <= i-th degree of th + ddeg*(i-th degree of other - i-th degree of lcoeff of other)
2531       double ans=1;
2532       for (int i=0;i<th.dim;++i){
2533 	d[i]=d1[i]+(ddeg+1)*(d2[i]-d3[i])+1;
2534 	int j=1;
2535 	// round to 2^
2536 	for (;;j++){
2537 	  if (!(d[i] >>= 1))
2538 	    break;
2539 	}
2540 	d[i] = 1 << j;
2541 	ans = ans*unsigned(d[i]);
2542 	if (ans/RAND_MAX>RAND_MAX)
2543 	  break;
2544       }
2545       if (ans<RAND_MAX){
2546 	if (modulo.type==_INT_ && modulo.val<46340 && modulo.val>0){
2547 	  // convert everything to integers
2548 	  vector< T_unsigned<int,unsigned> > p1,p2,quot,remain;
2549 	  vector<unsigned> vars(th.dim);
2550 	  vars[th.dim-1]=1;
2551 	  for (int i=th.dim-2;i>=0;--i){
2552 	    vars[i]=d[i+1]*vars[i+1];
2553 	  }
2554 	  if (debug_infolevel>1)
2555 	    CERR << "divrem convert " << CLOCK() << '\n';
2556 	  if (convert(th,d,p1,modulo.val) && convert(other,d,p2,modulo.val)){
2557 	    if (debug_infolevel>1)
2558 	      CERR << "hashdivrem begin " << CLOCK() << '\n';
2559 	    if (hashdivrem<int,unsigned>(p1,p2,quot,remain,vars,modulo.val,0.0,false)==1){
2560 	      if (debug_infolevel>1)
2561 		CERR << "hashdivrem end " << CLOCK() << '\n';
2562 	      convert(quot,d,quo);
2563 	      convert(remain,d,r);
2564 	      return true;
2565 	    }
2566 	    else
2567 	      return false;
2568 	  }
2569 	} // end modulo.type==_INT
2570       } // end ans < RAND_MAX
2571       if (ans/RAND_MAX<RAND_MAX){
2572 	if (modulo.type==_INT_ && modulo.val<46340 && modulo.val>0){
2573 	  // convert everything to integers
2574 	  vector< T_unsigned<int,ulonglong> > p1,p2,quot,remain;
2575 	  vector<ulonglong> vars(th.dim);
2576 	  vars[th.dim-1]=1;
2577 	  for (int i=th.dim-2;i>=0;--i){
2578 	    vars[i]=d[i+1]*vars[i+1];
2579 	  }
2580 	  if (convert(th,d,p1,modulo.val) && convert(other,d,p2,modulo.val)){
2581 	    if (hashdivrem<int,ulonglong>(p1,p2,quot,remain,vars,modulo.val,0.0,false)==1){
2582 	      convert(quot,d,quo);
2583 	      convert(remain,d,r);
2584 	      return true;
2585 	    }
2586 	    else
2587 	      return false;
2588 	  }
2589 	} // end modulo.type==_INT
2590       } // end ans/RAND_MAX < RAND_MAX
2591     } // end if ddeg>2 && os>10
2592 #endif //NO_TEMPLATE_MULTGCD
2593     tensor<gen> b0(Tnextcoeff<gen>(it,other.coord.end()));
2594     r=th;
2595     tensor<gen> q(b0.dim),q_other(th.dim);
2596     while ( (rdeg=r.lexsorted_degree()) >=bdeg){
2597       it=r.coord.begin();
2598       tensor<gen> a0(Tnextcoeff<gen>(it,r.coord.end())),tmp(a0.dim);
2599       if (!divremmod(a0,b0,modulo,q,tmp) || !tmp.coord.empty())
2600 	return false;
2601       q=q.untrunc1(rdeg-bdeg);
2602       quo=quo+q;
2603       mulpoly(q,other,q_other,modulo);
2604       r=smod(r-q_other,modulo);
2605       if (r.coord.empty())
2606 	return true;
2607     }
2608     return true;
2609   }
2610 
2611 
pow(const polynome & p,const gen & n)2612   polynome pow(const polynome & p,const gen & n){
2613     polynome res(p.dim);
2614     if (!n.is_integer()){
2615 #ifdef NO_STDEXCEPT
2616       res.coord.push_back(monomial<gen>(gensizeerr(gettext("gausspol.cc/pow")),p.dim));
2617       return res;
2618 #else
2619       setsizeerr(gettext("gausspol.cc/pow"));
2620 #endif
2621     }
2622     int i=n.to_int();
2623     if (!powpoly(p,i,res)){
2624 #ifdef NO_STDEXCEPT
2625       res.coord.clear();
2626       res.coord.push_back(monomial<gen>(gensizeerr(gettext("gausspol.cc/pow")),p.dim));
2627 #else
2628       setsizeerr(gettext("gausspol.cc/pow"));
2629 #endif
2630     }
2631     return res;
2632   }
2633 
pow(const polynome & p,int n)2634   polynome pow(const polynome & p, int  n){
2635     polynome res(p.dim);
2636     powpoly(p,n,res);
2637     return res;
2638   }
2639 
powmod1(const polynome & p,int n,const gen & modulo)2640   static polynome powmod1(const polynome &p,int n,const gen & modulo){
2641     switch (n) {
2642     case 0:
2643       return polynome(gen(1),p.dim);
2644     case 1:
2645       return p;
2646     default:
2647       polynome temp(powmod(p,n/2,modulo));
2648       if (n%2)
2649 	return (temp * temp * p) % modulo;
2650       else
2651 	return (temp*temp) % modulo;
2652     }
2653   }
2654 
powmod(const polynome & p,int n,const gen & modulo)2655   polynome powmod(const polynome &p,int n,const gen & modulo){
2656     if (p.dim<2)
2657       return powmod1(p,n,modulo);
2658     polynome res(gen(1),p.dim);
2659     for (int i=0;i<n;i++)
2660       res=(res*p) % modulo;
2661     return res;
2662   }
2663 
exact_inplace(polynome & P)2664   void exact_inplace(polynome & P){
2665     vector< monomial<gen> >::iterator it=P.coord.begin(),itend=P.coord.end();
2666     for (;it!=itend;++it)
2667       it->value=exact(it->value,context0);
2668   }
2669 
evalf_inplace(polynome & P)2670   void evalf_inplace(polynome & P){
2671     vector< monomial<gen> >::iterator it=P.coord.begin(),itend=P.coord.end();
2672     for (;it!=itend;++it)
2673       it->value=evalf(it->value,1,context0);
2674   }
2675 
2676   // Ducos: optimizations of the subresultant algorithm
2677 
2678   // n=d-1-e, d=degree(Sd), e=degree(Sd1), Se=(lc(Sd1)^n*Sd1)/lc(Sd)^n
ducos_e(const polynome & Sd,const polynome & sd,const polynome & Sd1,polynome & Se)2679   void ducos_e(const polynome & Sd,const polynome & sd,const polynome & Sd1,polynome & Se){
2680     int n=Sd.lexsorted_degree()-Sd1.lexsorted_degree()-1;
2681     if (!n){
2682       Se=Sd1;
2683       return;
2684     }
2685     if (n==1){
2686       Se=(Tfirstcoeff(Sd1)*Sd1)/sd;
2687       return;
2688     }
2689     // n>=2
2690     polynome sd1(Tfirstcoeff(Sd1)),s((sd1*sd1)/sd);
2691     for (int j=2;j<n;++j){
2692       s=(s*sd1)/sd;
2693     }
2694     Se=(s*Sd1)/sd;
2695   }
2696 
2697   // compute S_{e-1}
ducos_e1(const polynome & A,const polynome & Sd1,const polynome & Se,const polynome & sd,polynome & res)2698   void ducos_e1(const polynome & A,const polynome & Sd1,const polynome & Se,const polynome & sd,polynome & res){
2699     int d=A.lexsorted_degree(),e=Sd1.lexsorted_degree(),dim=A.dim;
2700     if (debug_infolevel>1)
2701       CERR << CLOCK()*1e-6 << "cducos_e1 begin d=" << d << '\n';
2702     polynome cd1(Tfirstcoeff(Sd1)),se(Tfirstcoeff(Se));
2703     index_t sh(dim);
2704 #if 0
2705     vector<polynome> Hv;
2706     for (int j=0;j<e;++j){
2707       sh[0]=j;
2708       Hv.push_back(se.shift(sh));
2709     }
2710 #else
2711     vector<polynome> Hv(e);
2712     Hv.reserve(d);
2713 #endif
2714     sh[0]=e;
2715     Hv.push_back(se.shift(sh)-Se);
2716     for (int j=e+1;j<d;++j){
2717       polynome XHj1(Hv.back());
2718       sh[0]=1; XHj1=XHj1.shift(sh); // X*H_{j-1}
2719       polynome piXHj1(A.dim);
2720       if (XHj1.lexsorted_degree()-e>=0)
2721 	piXHj1=XHj1.Tcoeffs() [XHj1.lexsorted_degree()-e].untrunc1();
2722       XHj1=XHj1-(piXHj1*Sd1)/cd1;
2723       Hv.push_back(XHj1);
2724     }
2725     polynome D(A.dim),DA(A.dim); // sum_{j<d} pi_j(A)*H_j/lc(A)
2726 #if 1
2727     vector<polynome> Av(A.Tcoeffs());
2728 #else
2729     vector<polynome> Av; A.Tcoeffs(Av);
2730 #endif
2731     // split next loop in 2 parts, because Hv indexes lower than e are straightforward
2732     if (debug_infolevel>1)
2733       CERR << CLOCK()*1e-6 << " ducos_e1 D begin" << '\n';
2734     for (int j=e-1;j>=0;--j){
2735       sh[0]=j;
2736 #if 0
2737       D.append((Av[Av.size()-1-j]*se.trunc1()).untrunc1().shift(sh));
2738 #else
2739       D.append(Av[Av.size()-1-j].untrunc1()*se.shift(sh));
2740 #endif
2741     }
2742     if (debug_infolevel>1)
2743       CERR << CLOCK()*1e-6 << " ducos_e1 D j=e " << e << "<" << d << '\n';
2744     for (int j=e;j<d;++j){
2745       D = D + Av[Av.size()-1-j].untrunc1()*Hv[j];
2746     }
2747     if (debug_infolevel>1)
2748       CERR << CLOCK()*1e-6 << " ducos_e1 D end, start division" << '\n';
2749 #if 1
2750     D = D/Av.front().untrunc1();
2751 #else
2752     if (!is_one(Av.front())){
2753       polynome quo(dim),rem(dim);
2754       divrem1(D,Av.front().untrunc1(),quo,rem,3,false);
2755       D.coord.swap(quo.coord);
2756     }
2757 #endif
2758     if (debug_infolevel>1)
2759       CERR << CLOCK()*1e-6 << " ducos_e1 D ready" << '\n';
2760     polynome Hd1(Hv.back());
2761     sh[0]=1;
2762     Hd1=Hd1.shift(sh); // X*Hd1
2763 #if 1
2764     res=(cd1*(Hd1+D)-(Hd1.coeff(e).untrunc1()*Sd1));
2765 #else
2766     res=(cd1*(Hd1+D)-(Hd1.Tcoeffs()[Hd1.lexsorted_degree()-1-e]).untrunc1()*Sd1);
2767 #endif
2768     if (debug_infolevel>1)
2769       CERR << CLOCK()*1e-6 << " ducos_e1 D final division" << '\n';
2770 #if 1
2771     res=res/sd;
2772 #else
2773     if (!is_one(sd)){
2774       polynome quo(dim),rem(dim);
2775       divrem1(res,sd,quo,rem,3,false);
2776       res.coord.swap(quo.coord);
2777     }
2778 #endif
2779     if (debug_infolevel>1)
2780       CERR << CLOCK()*1e-6 << " ducos_e1 end" << '\n';
2781     if ( (d-e+1)%2)
2782       res=-res;
2783   }
2784 
subresultant(const polynome & P,const polynome & Q,polynome & C,bool ducos)2785   void subresultant(const polynome & P,const polynome & Q,polynome & C,bool ducos){
2786     int dim=P.dim;
2787     if (dim==1){
2788       gen c;
2789       vecteur p,q;
2790       polynome2poly1(P,1,p);
2791       polynome2poly1(Q,1,q);
2792       subresultant(p,q,c);
2793       C=polynome(monomial<gen>(c,1));
2794       return;
2795     }
2796     int a=P.partial_degree(2);
2797     int b=Q.partial_degree(2);
2798     int m=P.lexsorted_degree();
2799     int n=Q.lexsorted_degree();
2800     // first estimate n*(a-m)+m*b
2801     int d1=n*(a-m)+m*b;
2802     gen coeffP;
2803     if (!ducos && !interpolable_resultant(P,d1,coeffP,false,context0)) ducos=true;
2804     if (!ducos && !interpolable_resultant(Q,d1,coeffP,false,context0)) ducos=true;
2805     //gen Pg=a*gen(m)*comb(m+dim-2,dim-2);
2806     //gen Qg=b*gen(n)*comb(n+dim-2,dim-2);
2807     if (//1 ||
2808 	!ducos && giacmin(m,n)>2 && dim<4 && P.coord.size()>=m && Q.coord.size() >= n
2809 	// && Pg.type==_INT_ && P.coord.size()>=Pg.val/2 && Qg.type==_INT_ && Q.coord.size()>=Qg.val/2
2810 	){
2811       double iclock=CLOCK()*1e-6;
2812       // for dense inputs, interpolate
2813       polynome pp0(P);
2814       pp0.reorder(transposition(0,1,dim));
2815       polynome qp0(Q);
2816       qp0.reorder(transposition(0,1,dim));
2817       // second estimate
2818       a=pp0.lexsorted_degree();
2819       b=qp0.lexsorted_degree();
2820       // a*n+b*m
2821       int d2=a*n+b*m;
2822       int d=giacmin(d1,d2);
2823       // interpolation
2824       vecteur vp,vq,vp0,vq0,X(d+1),Y(d+1);
2825       polynome2poly1(pp0,1,vp);
2826       pp0=firstcoeff(P).trunc1();
2827       polynome2poly1(pp0,1,vp0);
2828       polynome2poly1(qp0,1,vq);
2829       qp0=firstcoeff(Q).trunc1();
2830       polynome2poly1(qp0,1,vq0);
2831       int j=-d/2;
2832       if (coeffP.type==_USER)
2833 	j=0;
2834       for (int i=0;i<=d;++i,++j){
2835 	if (!debug_infolevel){
2836 	  double cclock=CLOCK()*1e-6;
2837 	  if (cclock-iclock>15)
2838 	    debug_infolevel=1;
2839 	}
2840 	if (debug_infolevel && (i%16==0))
2841 	  CERR << CLOCK()*1e-6 << " interp horner, loop index " << i << '\n';
2842 	gen xi;
2843 	for (;;++j){
2844 	  // find evaluation preserving degree in x
2845 	  if (0 && j==0)
2846 	    CERR << "j" << '\n';
2847 	  xi=interpolate_xi(j,coeffP);
2848 	  gen hp=horner(vp0,xi);
2849 	  gen hq=horner(vq0,xi);
2850 	  if (!is_zero(hp) && !is_zero(hq))
2851 	    break;
2852 	}
2853 	X[i]=xi;
2854 	gen gp=horner(vp,xi);
2855 	gen gq=horner(vq,xi);
2856 	if (debug_infolevel && (i%16==0))
2857 	  CERR << CLOCK()*1e-6 << " interp resultant evaled at " << j << ", " << 100*double(i)/(d+1) << "% done" << '\n';
2858 	if (gp.type==_POLY && gq.type==_POLY){
2859 	  Y[i]=resultant(*gp._POLYptr,*gq._POLYptr);
2860 	  continue;
2861 	}
2862 	if (gp.type==_POLY){
2863 	  Y[i]=pow(gq,gp._POLYptr->lexsorted_degree(),context0);
2864 	  continue;
2865 	}
2866 	if (gq.type==_POLY){
2867 	  Y[i]=pow(gp,gq._POLYptr->lexsorted_degree(),context0);
2868 	  continue;
2869 	}
2870 	Y[i]=1;
2871       }
2872       if (debug_infolevel)
2873 	CERR << CLOCK()*1e-6 << " interp dd " << '\n';
2874       vecteur R=divided_differences(X,Y);
2875       if (debug_infolevel)
2876 	CERR << CLOCK()*1e-6 << " interp build " << '\n';
2877       modpoly resp(1,R[d]),tmp; // cst in y
2878       for (int i=d-1;i>=0;--i){
2879 	operator_times(resp,makevecteur(1,-X[i]),0,tmp);
2880 	if (tmp.empty())
2881 	  tmp=vecteur(1,R[i]);
2882 	else
2883 	  tmp.back() += R[i];
2884 	tmp.swap(resp);
2885       }
2886       poly12polynome(resp,2,C,dim);
2887       return;
2888     }
2889     int d=P.lexsorted_degree(),e=Q.lexsorted_degree();
2890     if (d<e){
2891       subresultant(Q,P,C,true);
2892       // adjust sign
2893       if ((d*e)%2) C=-C;
2894       return;
2895     }
2896     if (e==0){
2897       if (Q.coord.empty()){
2898 	C=Q;
2899 	return;
2900       }
2901       C=pow(Q,d);
2902       return;
2903     }
2904     polynome sd(pow(Tfirstcoeff(Q),d-e)), A(Q),B(P.dim),quo(P.dim),tmp(P.dim);
2905     P.TPseudoDivRem(-Q,quo,B,tmp);
2906     for (unsigned step=0;;++step){
2907       d=A.lexsorted_degree(),e=B.lexsorted_degree();
2908       if (B.coord.empty()){
2909 	C=B;
2910 	return ;
2911       }
2912       int delta=d-e;
2913       if (delta>1){
2914 	polynome sd(Tfirstcoeff(A));
2915 	if (step==0)
2916 	  sd=pow(sd,P.lexsorted_degree()-Q.lexsorted_degree());
2917 	ducos_e(A,sd,B,C);
2918       }
2919       else
2920 	C=B;
2921       if (e==0){
2922 	// adjust sign: already done by doing pseudodivrem(-Q,...)
2923 	//if ((P.lexsorted_degree()*Q.lexsorted_degree())%2) C=-C;
2924 	return;
2925       }
2926       ducos_e1(A,B,C,sd,B);
2927       A.coord.swap(C.coord); // A=C;
2928       sd=Tfirstcoeff(A);
2929     }
2930   }
2931 
subresultant(const polynome & P,const polynome & Q,gen & c,polynome & C,bool ducos)2932   void subresultant(const polynome & P,const polynome & Q,gen & c,polynome & C,bool ducos){
2933     polynome p(P),q(Q);
2934     gen pz=ppz(p),qz=ppz(q);
2935     gen coefft,coeffqt;
2936     int pt=coefftype(p,coefft),qt=coefftype(q,coeffqt);
2937     polynome g;
2938     c=pow(pz,q.lexsorted_degree())*pow(qz,p.lexsorted_degree());
2939     if (pt==0 && qt==0){
2940       if (P.dim==1 && p.lexsorted_degree()>MODRESULTANT && q.lexsorted_degree()>MODRESULTANT){
2941 	gen r=mod_resultant(polynome2poly1(p,1),polynome2poly1(q,1),0.0);
2942 	c=c*r;
2943 	if (is_zero(r))
2944 	  C.coord.clear();
2945 	else
2946 	  poly12polynome(vecteur(1,1),1,C);
2947 	return;
2948       }
2949       // try gcd only if it is fast (integer coefficients for example)
2950       g=gcd(p,q);
2951       if (g.lexsorted_degree()){
2952 	C.coord.clear();
2953 	return;
2954       }
2955     }
2956     else {
2957       g=Tlgcd(p);
2958       Tlgcd(q,g);
2959     }
2960     if (!is_one(g)){
2961       p=p/g;
2962       q=q/g;
2963     }
2964     subresultant(p,q,C,ducos);
2965     if (!is_one(g)){
2966       int expo=p.lexsorted_degree()+q.lexsorted_degree();
2967       for (int i=0;i<expo;++i)
2968 	C=g*C;
2969     }
2970   }
2971 
resultant_sylvester(const polynome & p,const polynome & q,vecteur & pv,vecteur & qv,matrice & S,gen & determinant)2972   bool resultant_sylvester(const polynome &p,const polynome &q,vecteur &pv,vecteur &qv,matrice & S,gen & determinant){
2973     polynome2poly1(p,1,pv);
2974     polynome2poly1(q,1,qv);
2975     sylvester(pv,qv,S);
2976     vecteur pivots;
2977     matrice mres;
2978     int s=int(S.size());
2979     if (!mrref(S,mres,pivots,determinant,0,s,0,s,
2980 	       /* fullreduction */0,0,false/* no conversion*/,1/* guess algorithm */,1/* determinant */,
2981 	       context0))
2982       return false;
2983     return true;
2984   }
2985 
resultant_sylvester(const polynome & p,const polynome & q,matrice & S,polynome & res)2986   bool resultant_sylvester(const polynome &p,const polynome &q,matrice & S,polynome & res){
2987     vecteur pv,qv;
2988     gen determinant;
2989     if (!resultant_sylvester(p,q,pv,qv,S,determinant))
2990       return false;
2991     if (determinant.type==_POLY)
2992       res=determinant._POLYptr->untrunc1();
2993     else
2994       res=polynome(monomial<gen>(determinant,p.dim));
2995     return true;
2996   }
2997 
resultant(const polynome & p,const polynome & q)2998   polynome resultant(const polynome & p,const polynome & q){
2999     // polynomial subresultant does not work if p and q have approx coeff
3000     if (p.coord.empty())
3001       return p;
3002     if (q.coord.empty())
3003       return q;
3004     bool approx=has_num_coeff(p) || has_num_coeff(q);
3005     if (p.dim==1){
3006       if (approx
3007 	  // || (p.lexsorted_degree()>=GIAC_PADIC/2 && q.lexsorted_degree()>=GIAC_PADIC/2)
3008 	  ){
3009 	matrice S; polynome res(p.dim);
3010 	if (resultant_sylvester(p,q,S,res))
3011 	  return res;
3012       }
3013     }
3014     if (approx){
3015       polynome P(p),Q(q);
3016       exact_inplace(P); exact_inplace(Q);
3017       polynome res=Tresultant<gen>(P,Q);
3018       evalf_inplace(res);
3019       return res;
3020     }
3021     double pq=double(p.coord.size())*q.coord.size();
3022     unsigned dim=p.dim;
3023 #if 0 // def HAVE_LIBPARI // : PARI is faster but has problems with some large inputs
3024     // we must keep the same variable ordering than in PARI
3025     if (dim>=2 && dim<=4 && pq>256 && p.coord.size()>4 && q.coord.size()>4){
3026       gen coefft,coeffqt;
3027       int pt=coefftype(p,coefft),qt=coefftype(q,coeffqt);
3028       if (pt==0 && qt==0){
3029 	// PARI call
3030 	vecteur lv;
3031 	if (dim==2) lv=makevecteur(x__IDNT_e,y__IDNT_e);
3032 	if (dim==3) lv=makevecteur(x__IDNT_e,y__IDNT_e,z__IDNT_e);
3033 	if (dim==4) lv=makevecteur(x__IDNT_e,y__IDNT_e,z__IDNT_e,t__IDNT_e);
3034 	gen P=r2sym(p,lv,context0),Q=r2sym(q,lv,context0),res;
3035 	if (pari_polresultant(P,Q,lv,res,context0)){
3036 	  res=sym2r(res,lv,context0);
3037 	  if (res.type==_POLY){
3038 #if 0
3039 	    polynome res1; subresultant(p,q,res1,true);
3040 	    if (res!=res1){
3041 	      cerr << res._POLYptr->coord.size() << '\n';
3042 	      return res1;
3043 	    }
3044 #endif
3045 	    return *res._POLYptr;
3046 	  }
3047 	}
3048       }
3049     }
3050 #endif // HAVE_LIBPARI
3051     polynome R(p.dim); gen r;
3052     subresultant(p,q,r,R,false);
3053     return r*R;
3054 #if 0
3055     polynome R1(Tresultant<gen>(p,q));
3056     // COUT << R << "," << R1 << '\n';
3057     if (R!=R1)
3058       COUT << "error " << '\n';
3059     return R1;
3060 #endif
3061   }
3062 
lgcd(const polynome & p)3063   polynome lgcd(const polynome & p){
3064     return Tlgcd<gen>(p);
3065   }
3066 
ppz(polynome & p,bool divide)3067   gen ppz(polynome & p,bool divide){
3068 #ifdef USE_GMP_REPLACEMENTS
3069     return Tppz(p,divide);
3070 #else
3071     vector< monomial<gen> >::iterator it=p.coord.begin(),itend=p.coord.end();
3072     if (it==itend)
3073       return 1;
3074     gen res=(itend-1)->value;
3075     for (it=p.coord.begin();it!=itend-1;++it){
3076       res=gcd(res,it->value,context0);
3077       if (is_one(res))
3078 	return 1;
3079     }
3080     if (!divide)
3081       return res;
3082     if (res.type==_INT_ && res.val>0){
3083       for (it=p.coord.begin();it!=itend;++it){
3084 	if (it->value.type!=_ZINT || it->value.ref_count()>1)
3085 	  it->value=it->value/res;
3086 	else
3087 	  mpz_divexact_ui(*it->value._ZINTptr,*it->value._ZINTptr,res.val);
3088       }
3089       return res;
3090     }
3091     if (res.type==_ZINT){
3092       for (it=p.coord.begin();it!=itend;++it){
3093 	if (it->value.type!=_ZINT || it->value.ref_count()>1)
3094 	  it->value=it->value/res;
3095 	else
3096 	  mpz_divexact(*it->value._ZINTptr,*it->value._ZINTptr,*res._ZINTptr);
3097       }
3098       return res;
3099     }
3100     for (it=p.coord.begin();it!=itend;++it){
3101       it->value=it->value/res;
3102     }
3103     return res;
3104 #endif
3105   }
3106 
3107   // Find the content of p with respect to the 1st variable
3108   // p=p(x1,...,xn)=poly in x1 with coeff depending on x2,..,xn
3109   // content wrt x1 depends on x2,...,xn
lgcdmod(const polynome & p,const gen & modulo,polynome & pgcd)3110   void lgcdmod(const polynome & p,const gen & modulo,polynome & pgcd){
3111     if (!p.dim){
3112       pgcd=p;
3113       return ;
3114     }
3115     pgcd=pgcd.trunc1();
3116     vector< monomial<gen> >::const_iterator it=p.coord.begin();
3117     vector< monomial<gen> >::const_iterator itend=p.coord.end();
3118     // vector< monomial<gen> >::const_iterator itbegin=it;
3119     for (;it!=itend;){
3120       if (is_one(pgcd))
3121 	break;
3122       pgcd=gcdmod(pgcd,Tnextcoeff<gen>(it,itend),modulo);
3123     }
3124     if (pgcd.coord.empty()){
3125       index_m i;
3126       for (int j=0;j<p.dim;j++)
3127 	i.push_back(0);
3128       pgcd.coord.push_back(monomial<gen>(gen(1),i));
3129     }
3130     else
3131       pgcd=pgcd.untrunc1();
3132   }
3133 
3134   // Split a multivariate poly X_1...X_n as multivar X_dim+1...X_n
3135   // with coeff multivar poly of X_1..X_dim
split(const polynome & p,int inner_dim)3136   polynome split(const polynome & p,int inner_dim){
3137     int outer_dim=p.dim-inner_dim;
3138     polynome cur_inner(inner_dim);
3139     polynome res(outer_dim);
3140     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
3141     for (; it!=itend;++it){
3142       index_t outer_index(it->index.begin()+inner_dim,it->index.end());
3143       index_t inner_index(it->index.begin(),it->index.begin()+inner_dim);
3144       cur_inner=polynome(monomial<gen>(it->value,inner_index));
3145       res=res+polynome(monomial<gen>(cur_inner,outer_index));
3146     }
3147     return res;
3148   }
3149 
3150   /*
3151 #ifdef HASH_MAP_NAMESPACE
3152   class hash_function_index_t {
3153   public:
3154     inline size_t operator () (const index_t & a) const {
3155       size_t r=0;
3156       index_t::const_iterator ita=a.begin(),itaend=a.end();
3157       for (;ita!=itaend;++ita){
3158 	r <<= 4;
3159 	r += (*ita) & 0xf;
3160       }
3161       return r;
3162     }
3163     hash_function_index_t() {};
3164   };
3165 
3166   typedef HASH_MAP_NAMESPACE::hash_map<index_t,polynome,hash_function_index_t> map_index_t_polynome;
3167 #else
3168   typedef std::map<index_t,polynome> map_index_t_polynome;
3169 #endif
3170   */
3171 
3172   typedef std::map<index_t,polynome> map_index_t_polynome;
3173 
3174   // return true if content=1 is detected
split(const polynome & p,int inner_dim,map_index_t_polynome & res)3175   static bool split(const polynome & p,int inner_dim,map_index_t_polynome & res){
3176     // int outer_dim=p.dim-inner_dim;
3177     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
3178     for (; it!=itend;++it){
3179       index_t cur_index= it->index.iref();
3180       index_t outer_index(it->index.begin()+inner_dim,it->index.end());
3181       index_t inner_index(it->index.begin(),it->index.begin()+inner_dim);
3182       map_index_t_polynome::iterator jt=res.find(outer_index),jtend=res.end();
3183       if (jt==jtend){
3184 	if (is_zero(inner_index))
3185 	  return true;
3186 	res[outer_index]=polynome(monomial<gen>(it->value,inner_index));
3187       }
3188       else
3189 	jt->second.coord.push_back(monomial<gen>(it->value,inner_index));
3190     }
3191     return false;
3192   }
3193 
lcoeffn(const polynome & p)3194   gen lcoeffn(const polynome & p){
3195     int dim=p.dim;
3196     polynome res(dim);
3197     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
3198     if (it==itend)
3199       return 0;
3200     index_t i= it->index.iref();
3201     for (;it!=itend;++it){
3202       const index_t & j= it->index.iref();
3203       i[dim-1]=j[dim-1];
3204       if (i!=j)
3205 	break;
3206       res.coord.push_back(*it);
3207     }
3208     return res;
3209   }
3210 
lcoeff1(const polynome & p)3211   gen lcoeff1(const polynome & p){
3212     if (p.coord.empty())
3213       return zero;
3214     int inner_dim=1;
3215     // int outer_dim=p.dim-inner_dim;
3216     polynome cur_inner(inner_dim);
3217     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
3218     index_t::const_iterator jt0 = it->index.begin(),jtend=it->index.end(),jt,kt0,kt;
3219     for (; it!=itend;++it){
3220       kt0 = it->index.begin();
3221       for (jt=jt0+inner_dim,kt=kt0+inner_dim;jt!=jtend;++kt,++jt){
3222 	if (*kt<*jt)
3223 	  break;
3224 	if (*kt>*jt){
3225 	  jt0=kt0;
3226 	  jtend=kt0+p.dim;
3227 	  cur_inner.coord.clear();
3228 	  jt=jtend;
3229 	  break;
3230 	}
3231       }
3232       if (jt==jtend)
3233 	cur_inner.coord.push_back(monomial<gen>(it->value,index_t(kt0,kt0+inner_dim)));
3234     }
3235     return cur_inner;
3236   }
3237 
content1mod(const polynome & p,const gen & modulo,bool setdim)3238   polynome content1mod(const polynome & p,const gen & modulo,bool setdim){
3239     if (p.coord.empty()){
3240 #ifndef NO_STDEXCEPT
3241       setsizeerr(gettext("content1mod"));
3242 #endif
3243       return polynome(monomial<gen>(1,p.dim));
3244     }
3245     if (p.coord.size()==1){
3246       int n=p.coord.front().index.front();
3247       polynome c(monomial<gen>(p.coord.front().value,index_t(1,n)));
3248       if (setdim)
3249 	change_dim(c,p.dim);
3250       return c;
3251     }
3252     // New code
3253     map_index_t_polynome m;
3254     polynome c(1);
3255     if (!split(p,1,m)){
3256       int c0=RAND_MAX,i0;
3257       map_index_t_polynome::iterator it=m.begin(),itend=m.end();
3258       if (m.size()==1)
3259 	c=it->second;
3260       else {
3261 	for (;c0 && it!=itend;++it){
3262 	  if (!it->second.coord.empty() && (i0=it->second.coord.front().index.front())<c0){
3263 	    c=it->second;
3264 	    c0=i0;
3265 	  }
3266 	}
3267 	it=m.begin();
3268 	for (;it!=itend;++it){
3269 	  if (!c.coord.empty() &&c.coord.front().index.front()==0 ){
3270 	    c=polynome(plus_one,1);
3271 	    break;
3272 	  }
3273 	  c=gcdmod(c,it->second,modulo);
3274 	}
3275 	/* Old code
3276 	   polynome lp(split(p,1)),c(1);
3277 	   vector< monomial<gen> >::const_iterator it=lp.coord.begin(),itend=lp.coord.end();
3278 	   for (;it!=itend;++it){
3279 	   if (it->value.type==_POLY)
3280 	   c=gcdmod(c,*it->value._POLYptr,modulo);
3281 	   else {
3282 	   c=polynome(plus_one,1); // was c=polynome(plus_one,p.dim-1);
3283 	   break;
3284 	   }
3285 	   }
3286 	*/
3287       } // end if itend==it+1
3288     } // end if (!split()) : i.e. if the content is not trivially 1
3289     else
3290       c=polynome(plus_one,1);
3291     if (setdim)
3292       change_dim(c,p.dim);
3293     return c;
3294   }
3295 
pp1mod(const polynome & p,const gen & modulo)3296   polynome pp1mod(const polynome & p,const gen & modulo){
3297     polynome q(p.dim),r(p.dim);
3298     polynome tmp(content1mod(p,modulo));
3299     // CERR << "pp1mod " << tmp << '\n';
3300     divremmod(p,tmp,modulo,q,r);
3301     return q;
3302   }
3303 
3304   // Find non zeros coeffs of p
find_nonzero(const polynome & p,index_t & res)3305   int find_nonzero(const polynome & p,index_t & res){
3306     res.clear();
3307     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
3308     if (it==itend)
3309       return 0;
3310     int old_deg=it->index.front(),cur_deg=0;
3311     int nzeros=0;
3312     res.push_back(1);
3313     for (;it!=itend;++it){
3314       cur_deg=it->index.front();
3315       if (cur_deg!=old_deg){
3316 	nzeros += old_deg - cur_deg -1 ;
3317 	for (int i=old_deg-cur_deg;i>1;--i)
3318 	  res.push_back(0);
3319 	res.push_back(1);
3320 	old_deg=cur_deg;
3321       }
3322     }
3323     if (cur_deg){
3324       nzeros += cur_deg;
3325       for (int i=cur_deg;i>0;--i)
3326 	res.push_back(0);
3327     }
3328     return nzeros;
3329   }
3330 
degree2unsigned(index_t & deg,unsigned & u)3331   static bool degree2unsigned(index_t & deg,unsigned & u){
3332     u=1;
3333     index_t::iterator it=deg.begin(),itend=deg.end();
3334     for (;it!=itend;++it){
3335       ++(*it);
3336       u = u*unsigned(*it);
3337       if (u>RAND_MAX)
3338 	return false;
3339     }
3340     return true;
3341   }
3342 
3343   // p_orig and q_orig are primitive with respect to the main variable
3344   // p(x1,...,xn) q(x1,...,xn) viewed as p(x1) and q(x1)
3345   // d must be the same
mod_gcdmod(const polynome & p_orig,const polynome & q_orig,const gen & modulo,polynome & d,int gcddeg=0)3346   static void mod_gcdmod(const polynome &p_orig, const polynome & q_orig, const gen & modulo, polynome & d,int gcddeg=0){
3347     if (p_orig.coord.empty() || is_one(q_orig)){
3348       d=q_orig;
3349       return;
3350     }
3351     if (q_orig.coord.empty() || is_one(p_orig)){
3352       d=p_orig;
3353       return;
3354     }
3355     if (debug_infolevel)
3356       CERR << "gcdmod content dim " << d.dim << " " << CLOCK() << '\n';
3357     polynome p(p_orig.dim),q(q_orig.dim),r;
3358     vector<int_unsigned> pint,qint;
3359     index_t pintd=p_orig.degree(),qintd=q_orig.degree();
3360     unsigned pu,qu;
3361     // Make p and q primitive with respect to x2,...,xn
3362     // i.e. the coeff of p and q which are polynomials in x1
3363     // are relative prime
3364     // r is the gcd of the content in this sense
3365     bool docontent1mod=true;
3366     // bug there, if false is removed lwN and lwN1 do not work
3367     if (false &&
3368 	modulo.type==_INT_ && degree2unsigned(pintd,pu) && degree2unsigned(qintd,qu)){
3369       convert(p_orig,pintd,pint,modulo.val);
3370       convert(q_orig,qintd,qint,modulo.val);
3371       if (is_content_trivially_1(pint,pu/pintd.front()) && is_content_trivially_1(qint,qu/qintd.front()))
3372 	docontent1mod=false;
3373     }
3374     if (docontent1mod) {
3375       polynome pc(content1mod(p_orig,modulo)),qc(content1mod(q_orig,modulo));
3376       divremmod(p_orig,pc,modulo,p,r);
3377       divremmod(q_orig,qc,modulo,q,r);
3378       // CERR << "content end " << CLOCK() << '\n';
3379       change_dim(pc,1); change_dim(qc,1);
3380       r=gcdmod(pc,qc,modulo);
3381       change_dim(r,p.dim);
3382     }
3383     else {
3384       p=p_orig;
3385       q=q_orig;
3386       r=polynome(plus_one,p.dim);
3387     }
3388     // Find degree of gcd with respect to x1, more precisely gcddeg>=degree/x1
3389     // and compute data for the sparse modular algorithm
3390     index_t vzero; // coeff of vzero correspond to zero or non zero
3391     int nzero=1; // Number of zero coeffs
3392     vecteur alphav,gcdv; // Corresponding values of alpha and gcd at alpha
3393     if (!gcddeg){
3394       vecteur b(p.dim-1);
3395       for (int essai=0;essai<2;++essai){
3396 	if (essai)
3397 	  b=vranm(p.dim-1,0,0); // find another random point
3398 	polynome Fb(1),Gb(1);
3399 	// Fb and Gb are p and q where x2,...,xn are evaluated at b
3400 	if (!find_good_eval(p,q,Fb,Gb,b,(debug_infolevel>=2),modulo))
3401 	  break;
3402 	polynome Db(gcdmod(Fb,Gb,modulo)); // 1-d gcd wrt x1
3403 	int Dbdeg=Db.lexsorted_degree();
3404 	if (!Dbdeg){
3405 	  gcddeg=0;
3406 	  break;
3407 	}
3408 	if (!gcddeg){ // 1st gcd test
3409 	  gcddeg=Dbdeg;
3410 	  nzero=find_nonzero(Db,vzero);
3411 	}
3412 	else { // 2nd try
3413 	  if (Dbdeg<gcddeg){ // 1st try unlucky, restart 1st try
3414 	    gcddeg=Dbdeg;
3415 	    nzero=find_nonzero(Db,vzero);
3416 	    --essai;
3417 	  }
3418 	  else {
3419 	    if (Dbdeg>gcddeg) // 2nd try unlucky, restart 2nd try
3420 	      --essai;
3421 	    else { // Same gcd degree for 1st and 2nd try, keep this degree
3422 	      index_t tmp;
3423 	      nzero=find_nonzero(Db,tmp);
3424 	      if (nzero){
3425 		vzero = vzero | tmp;
3426 		// Recompute nzero, it is the number of 0 coeff of vzero
3427 		index_t::const_iterator it=vzero.begin(),itend=vzero.end();
3428 		for (nzero=0;it!=itend;++it){
3429 		  if (!*it) ++nzero;
3430 		}
3431 	      }
3432 	    }
3433 	  }
3434 	}
3435       }
3436     }
3437     else {
3438       gcddeg -= r.lexsorted_degree() ;
3439       nzero = 0; // No info available
3440     }
3441     if (!gcddeg){
3442       d=r;
3443       return;
3444     }
3445     d=polynome(p.dim);
3446     polynome interp(plus_one,p.dim);
3447     // gcd of leading coefficients of p and q viewed as poly in X_2...X_n
3448     // with coeff in Z[X_1]
3449     if (debug_infolevel)
3450       CERR << "gcdmod lcoeff1 dim " << d.dim << " " << CLOCK() << '\n';
3451     gen lp(lcoeff1(p)),lq(lcoeff1(q));
3452     polynome Delta(plus_one,p.dim);
3453     if ((lp.type==_POLY) && (lq.type==_POLY) )
3454       Delta=gcdmod(*lp._POLYptr,*lq._POLYptr,modulo);
3455     // we are now interpolating G=gcd(p,q)*a poly/x1
3456     // such that the leading coeff of G is Delta
3457     index_t pdeg(p.degree()),qdeg(q.degree());
3458     int spdeg=0,sqdeg=0;
3459     for (int i=1;i<p.dim;++i){
3460       spdeg += pdeg[i];
3461       sqdeg += qdeg[i];
3462     }
3463     index_t delta=index_min(index_t(pdeg.begin()+1,pdeg.end()),
3464 			    index_t(qdeg.begin()+1,qdeg.end()));
3465     int e=0; // number of evaluations
3466     int alpha=0;
3467     if (debug_infolevel>1)
3468       CERR << "gcdmod find alpha dim " << d.dim << " " << CLOCK() << '\n';
3469     for (;;++alpha){
3470       vecteur valpha;
3471       polynome palpha(p.dim-1),qalpha(q.dim-1);
3472       for (;alpha<modulo.val;++alpha){
3473 	valpha=vecteur(1,alpha);
3474 	gen tmp(peval(p,valpha,modulo,false,&pint));
3475 	if (is_zero(tmp))
3476 	  continue;
3477 	if (tmp.type!=_POLY){
3478 	  if (spdeg)
3479 	    continue;
3480 	  // gcd may only depend on first var
3481 	  d=r;
3482 	  return;
3483 	}
3484 	palpha=smod(*tmp._POLYptr,modulo);
3485 	tmp=peval(q,valpha,modulo,false,&qint);
3486 	if (is_zero(tmp))
3487 	  continue;
3488 	if (tmp.type!=_POLY){
3489 	  if (sqdeg)
3490 	    continue;
3491 	  d=r;
3492 	  return;
3493 	}
3494 	qalpha=smod(*tmp._POLYptr,modulo);
3495 	if ( palpha.lexsorted_degree()==pdeg[1] &&
3496 	     qalpha.lexsorted_degree()==qdeg[1] )
3497 	  break;
3498       }
3499       // palpha and qalpha are p and q evaluated at x1=alpha
3500       if (debug_infolevel>1)
3501 	CERR << "gcdmod eval " << alpha << " dim " << d.dim << " " << CLOCK() << '\n';
3502       if (alpha==modulo){
3503 #ifndef NO_STDEXCEPT
3504 	setsizeerr(gettext("Modgcd: no suitable evaluation point"));
3505 #endif
3506 	return ;
3507       }
3508       polynome g(gcdmod(palpha,qalpha,modulo));
3509       index_t gdeg(g.degree());
3510       // int gcd_plus_delta_deg=gcddeg+Delta.lexsorted_degree();
3511       if (gdeg==delta){
3512 	// Try spmod first
3513 	if (nzero){
3514 	  // Add alpha,g
3515 	  alphav.push_back(alpha);
3516 	  gcdv.push_back(g);
3517 	  if (gcddeg-nzero==e){
3518 	    // We have enough evaluations, let's try SPMOD
3519 	    // Build the matrix, each line has coeffs / vzero
3520 	    matrice m;
3521 	    for (int j=0;j<=e;++j){
3522 	      index_t::reverse_iterator it=vzero.rbegin(),itend=vzero.rend();
3523 	      vecteur line;
3524 	      for (gen p=alphav[j],pp=plus_one;it!=itend;++it,pp=smod(p*pp,modulo)){
3525 		if (*it)
3526 		  line.push_back( pp);
3527 	      }
3528 	      reverse(line.begin(),line.end());
3529 	      line.push_back(gcdv[j]);
3530 	      m.push_back(line);
3531 	    }
3532 	    // Reduce linear system modulo modulo
3533 	    gen det; vecteur pivots; matrice mred;
3534 	    // CERR << "SPMOD " << CLOCK() << '\n';
3535 	    modrref(m,mred,pivots,det,0,int(m.size()),0,int(m.front()._VECTptr->size())-1,true,false,modulo,false,0);
3536 	    // CERR << "SPMODend " << CLOCK() << '\n';
3537 	    if (!is_zero(det)){
3538 	      // Last column is the solution, it should be polynomials
3539 	      // that must be untrunced with index = to non-0 coeff of vzero
3540 	      polynome trygcd(p.dim);
3541 	      index_t::const_iterator it=vzero.begin(),itend=vzero.end();
3542 	      int deg=int(itend-it)-1;
3543 	      for (int pos=0;it!=itend;++it,--deg){
3544 		if (!*it)
3545 		  continue;
3546 		gen tmp=mred[pos][e+1]; // e+1=#of points -> last col
3547 		if (tmp.type==_POLY)
3548 		  trygcd=trygcd+tmp._POLYptr->untrunc1(deg);
3549 		else
3550 		  if (!is_zero(tmp))
3551 		    trygcd=trygcd+polynome(monomial<gen>(tmp,deg,1,p.dim));
3552 		++pos;
3553 	      }
3554 	      // Check if trygcd is the gcd!
3555 	      polynome pD(pp1mod(trygcd,modulo)),Q(p.dim),R(d.dim);
3556 	      divremmod(p,pD,modulo,Q,R);
3557 	      if (R.coord.empty()){
3558 		divremmod(q,pD,modulo,Q,R);
3559 		if (R.coord.empty()){
3560 		  pD=pD*r;
3561 		  d=smod(pD*invmod(pD.coord.front().value,modulo),modulo);
3562 		  return;
3563 		}
3564 	      }
3565 	    }
3566 	    // SPMOD not successful :-(
3567 	    nzero=0;
3568 	  } // end if gcddeg-nzero==e
3569 	} // end if (nzero)
3570 	if (debug_infolevel>1)
3571 	  CERR << "gcdmod interp dim " << d.dim << " " << CLOCK() << '\n';
3572 	polynome g1=(g*smod(peval(Delta,valpha,modulo),modulo))*invmod(g.coord.front().value,modulo);
3573 	gen tmp(g1-peval(d,valpha,modulo));
3574 	if (tmp.type==_POLY){
3575 	  g1=smod(*tmp._POLYptr,modulo);
3576 	  g1=g1.untrunc1();
3577 	}
3578 	else
3579 	  g1=polynome(tmp,p.dim);
3580 	d=d+g1*interp*invmod(peval(interp,valpha,modulo),modulo);
3581 	d=smod(d,modulo);
3582 	interp=interp*(polynome(monomial<gen>(plus_one,1,1,p.dim))-polynome(gen(alpha),p.dim));
3583 	++e;
3584 	if (e>gcddeg
3585 	    || is_zero(tmp)
3586 	    ){
3587 	  if (debug_infolevel)
3588 	    CERR << "gcdmod pp1mod dim " << d.dim << " " << CLOCK() << '\n';
3589 	  polynome pD(pp1mod(d,modulo)),Q(p.dim),R(d.dim);
3590 	  // This removes the polynomial in x1 that we multiplied by
3591 	  // (it was necessary to know the lcoeff of the interpolated poly)
3592 	  if (debug_infolevel)
3593 	    CERR << "gcdmod check dim " << d.dim << " " << CLOCK() << '\n';
3594 	  // Now, gcd divides pD for gcddeg+1 values of x1
3595 	  // degree(pD)<=degree(gcd)
3596 	  divremmod(p,pD,modulo,Q,R);
3597 	  if (debug_infolevel){
3598 	    CERR << "test * " << CLOCK() << '\n';
3599 	    polynome R2;
3600 	    mulpoly(pD,Q,R2,modulo);
3601 	    CERR << "test * end " << CLOCK() << '\n';
3602 	  }
3603 	  if (R.coord.empty()){
3604 	    divremmod(q,pD,modulo,Q,R);
3605 	    // If pD divides both P and Q, then the degree wrt variables
3606 	    // x2,...,xn is the right one (because it is <= since pD
3607 	    // divides the gcd and >= since pD(x1=one of the try) was a gcd
3608 	    // The degree in x is the right one because of the condition
3609 	    // on the lcoeff
3610 	    // Note that the division test might be much longer than the
3611 	    // interpolation itself (e.g. if the degree of the gcd is small)
3612 	    // but it seems unavoidable, for example if
3613 	    // P=Y-X+X(X-1)(X-2)(X-3)
3614 	    // Q=Y-X+X(X-1)(X-2)(X-4)
3615 	    // then gcd(P,Q)=1, but if we take Y=0, Y=1 or Y=2
3616 	    // we get gcddeg=1 (probably degree 1 for the gcd)
3617 	    // interpolation at X=0 and X=1 will lead to Y-X as candidate gcd
3618 	    // and even adding X=2 will not change it
3619 	    // We might remove division if we compute the cofactors of P and Q
3620 	    // if P=pD*cofactor is true for degree(P) values of x1
3621 	    // and same for Q, and the degrees wrt x1 of pD and cofactors
3622 	    // have sum equal to degree of P or Q then pD is the gcd
3623 	    if (R.coord.empty()){
3624 	      pD=pD*r;
3625 	      d=smod(pD*invmod(pD.coord.front().value,modulo),modulo);
3626 	      if (debug_infolevel)
3627 		CERR << "gcdmod found dim " << d.dim << " " << CLOCK() << '\n';
3628 	      return;
3629 	    }
3630 	  }
3631 	  if (debug_infolevel)
3632 	    CERR << "Gcdmod bad guess " << '\n';
3633 	  continue;
3634 	}
3635 	else
3636 	  continue;
3637       }
3638       if (gdeg[0]>delta[0]) // branch if all degree are >=
3639 	continue;
3640       if (delta[0]>=gdeg[0]){ // restart with g
3641 	gcdv=vecteur(1,g);
3642 	alphav=vecteur(1,alpha);
3643 	delta=gdeg;
3644 	g=(g*smod(peval(Delta,valpha,modulo),modulo))*invmod(g.coord.front().value,modulo);
3645 	d=g.untrunc1();
3646 	e=1;
3647 	interp=polynome(monomial<gen>(plus_one,1,1,p.dim))-polynome(gen(alpha),p.dim);
3648 	continue;
3649       }
3650     }
3651   }
3652 
psrgcdmod(polynome & a,polynome & b,const gen & modulo,polynome & prim)3653   void psrgcdmod(polynome & a,polynome & b,const gen & modulo,polynome & prim){
3654     // set auxiliary polynomials g and h to 1
3655     polynome g(gen(1),a.dim);
3656     polynome h(g),quo(g),r(g);
3657     while (!a.coord.empty()){
3658       int n=b.lexsorted_degree();
3659       int m=a.lexsorted_degree();
3660       if (!n) {// if b is constant (then b!=0), gcd=original lgcdmod
3661 	prim=polynome(gen(1),a.dim);
3662 	return ;
3663       }
3664       int ddeg=m-n;
3665       if (ddeg<0)
3666 	swap(a,b); // exchange a<->b may occur only at the beginning
3667       else {
3668 	polynome b0(firstcoeff(b));
3669 	divremmod(a*pow(b0,ddeg+1),b,modulo,quo,r); // division works always
3670 	if (r.coord.empty())
3671 	  break;
3672 	// remainder is non 0, loop continue: a <- b
3673 	a=b;
3674 	polynome temp(powmod(h,ddeg,modulo));
3675 	// now divides r by g*h^(m-n), result is the new b
3676         divremmod(r,g*temp,modulo,b,quo); // quo is the remainder here, not used
3677 	// new g=b0 and new h=b0^(m-n)*h/temp
3678 	if (ddeg==1) // the normal case, remainder deg. decreases by 1 each time
3679 	  h=b0;
3680 	else // not sure if it's better to keep temp or divide by h^(m-n+1)
3681 	  divremmod(pow(b0,ddeg)*h,temp,modulo,h,quo);
3682 	g=b0;
3683       }
3684     }
3685     // COUT << "Prim" << b << '\n';
3686     quo.coord.clear();
3687     lgcdmod(b,modulo,quo);
3688     divremmod(b,quo,modulo,prim,r);
3689     prim=smod(prim*invmod(prim.coord.front().value,modulo),modulo);
3690   }
3691 
contentgcdmod(const polynome & p,const polynome & q,const gen & modulo,polynome & cont,polynome & prim)3692   void contentgcdmod(const polynome &p, const polynome & q, const gen & modulo, polynome & cont,polynome & prim){
3693     if (p.coord.empty()){
3694       cont.coord.clear();
3695       lgcdmod(q,modulo,cont);
3696       polynome temp(cont.dim);
3697       divremmod(q,cont,modulo,prim,temp);
3698       return ;
3699     }
3700     if (q.coord.empty()){
3701       contentgcdmod(q,p,modulo,cont,prim);
3702       return;
3703     }
3704     if (p.dim!=q.dim){
3705 #ifndef NO_STDEXCEPT
3706       setsizeerr(gettext("gausspol.cc/contentgcdmod"));
3707 #endif
3708       return ;
3709     }
3710     // dp and dq are the "content" of p and q w.r.t. other variables
3711     polynome dp(p.dim), dq(p.dim);
3712     // CERR << p.dim << " " << CLOCK() << '\n';
3713     lgcdmod(p,modulo,dp);
3714     lgcdmod(q,modulo,dq);
3715     // CERR << "End " << p.dim << " " << CLOCK() << '\n';
3716     cont=gcdmod(dp.trunc1(),dq.trunc1(),modulo).untrunc1();
3717     if (!p.dim){
3718       prim=polynome(gen(1),0);
3719       return ;
3720     }
3721     // COUT << "Cont" << cont << '\n';
3722     polynome a(p.dim),b(p.dim),quo(p.dim),r(p.dim);
3723     // a and b are the primitive part of p and q
3724     divremmod(p,dp,modulo,a,r);
3725     divremmod(q,dq,modulo,b,r);
3726     if (modulo.val>=4*giacmin(p.lexsorted_degree(),q.lexsorted_degree())){
3727       mod_gcdmod(a,b,modulo,prim);
3728       return ;
3729     }
3730     psrgcdmod(a,b,modulo,prim);
3731   }
3732 
gcdmod_dim1(const polynome & p,const polynome & q,const gen & modulo,polynome & d,polynome & pcof,polynome & qcof,bool compute_cof,bool & real)3733   bool gcdmod_dim1(const polynome &p,const polynome & q,const gen & modulo,polynome & d,polynome & pcof,polynome & qcof,bool compute_cof,bool & real){
3734     real= poly_is_real(p) && poly_is_real(q);
3735     if (p.dim!=1)
3736       return false;
3737     if (q.dim!=1)
3738       return false;
3739     d.dim=pcof.dim=qcof.dim=1;
3740     if (real && modulo.type==_INT_ && gcdsmallmodpoly(p,q,modulo.val,d,pcof,qcof,compute_cof)){
3741       return true;
3742     }
3743     modpoly P(polynome2poly1(p,1));
3744     modpoly Q(polynome2poly1(q,1));
3745     environment envi;
3746     environment * env=&envi;
3747     env->modulo=modulo;
3748     env->pn=env->modulo;
3749     env->moduloon=true;
3750     env->complexe=true;
3751     modpoly R,PQ,PR;
3752     gcdmodpoly(P,Q,env,R);
3753     if (is_undef(R))
3754       return false;
3755     d=poly12polynome(R);
3756     if (compute_cof){
3757       DivRem(P,R,env,PQ,PR);
3758       pcof=poly12polynome(PQ);
3759       DivRem(Q,R,env,PQ,PR);
3760       qcof=poly12polynome(PQ);
3761     }
3762     return true;
3763   }
3764 
gcdmod(const polynome & p,const polynome & q,const gen & modulo)3765   polynome gcdmod(const polynome &p,const polynome & q,const gen & modulo){
3766 #ifndef NO_STDEXCEPT
3767     if (p.dim!=q.dim)
3768       setsizeerr(gettext("Bug!"));
3769 #endif
3770     if (p==q)
3771       return p;
3772     if (p.coord.empty())
3773       return q;
3774     if (q.coord.empty())
3775       return p;
3776     if (p.dim==1){
3777       polynome d(1),pd(1),qd(1);
3778       bool estreel;
3779       gcdmod_dim1(p,q,modulo,d,pd,qd,false,estreel);
3780       return d;
3781     }
3782     // Check that there are enough points for interpolation
3783     // Otherwise PSR
3784     if (modulo.val>=4*giacmin(p.lexsorted_degree(),q.lexsorted_degree())){
3785       polynome d(p.dim),pcof(p.dim),qcof(p.dim);
3786       if (modgcd(p,q,modulo,d,pcof,qcof,false))
3787 	return d;
3788 #ifdef TIMEOUT
3789       control_c();
3790 #endif
3791       if (ctrl_c || interrupted){
3792 	ctrl_c=false; interrupted=true;
3793 	d.coord.push_back(monomial<gen>(gensizeerr(gettext("Stopped by user interruption.")),d.dim));
3794 	return d;
3795       }
3796     }
3797     polynome a(smod(p*invmod(p.coord.front().value,modulo),modulo));
3798     polynome b(smod(q*invmod(q.coord.front().value,modulo),modulo));
3799     // Use evaluation points if enough available or modular psrh
3800     polynome prim(p.dim),cont(p.dim);
3801     contentgcdmod(a,b,modulo,prim,cont);
3802     if (debug_infolevel>10)
3803       COUT << "Prim" << prim << "Cont" << cont << '\n';
3804     return smod(prim*cont, modulo);
3805   }
3806 
3807   /*
3808     p and q are assumed to have integer content=1
3809     the leading coeff of d=gcd(p,q) divides the leading coeff of p and q
3810     we will therefore normalize modular gcds to have the gcd of the
3811     leading coeffs as leading coeff, and will try divisibility
3812     of it's smodular representant after division by the content
3813    */
gcd_modular_algo(polynome & p,polynome & q,polynome & d,bool compute_cof)3814   bool gcd_modular_algo(polynome &p,polynome &q, polynome &d,bool compute_cof){
3815     if (p.dim==1)
3816       return gcd_modular_algo1(p,q,d,compute_cof);
3817     polynome plgcd(p.dim), qlgcd(q.dim), pp(p.dim), qq(p.dim),gcdlgcd(p.dim);
3818     plgcd=lgcd(p);
3819     qlgcd=lgcd(q);
3820     pp=p/plgcd;
3821     qq=q/qlgcd;
3822     gcdlgcd=gcd(plgcd,qlgcd);
3823     gen gcdfirstcoeff(gcd(pp.coord.front().value, qq.coord.front().value,context0));
3824     int gcddeg= giacmin(pp.lexsorted_degree(),qq.lexsorted_degree());
3825     gen bound(pow(gen(2),gcddeg+1)* abs(gcdfirstcoeff,context0) * min(pp.norm(), qq.norm(),context0));
3826     gen modulo(nextprime(max(gcdfirstcoeff+1,gen(30000),context0)));
3827     gen productmodulo(1);
3828     polynome currentgcd(p.dim),p_simp(p.dim),q_simp(p.dim),rem(p.dim);
3829     // 30000 leaves many primes below the 2^15 bound
3830     for (;;modulo = nextprime(modulo+2)){
3831       // increment modulo to avoid modulo = 1 [4] so that it works in Z[i]
3832       while ( is_one(modulo % 4) || is_zero(gcdfirstcoeff % modulo))
3833 	modulo=nextprime(modulo+2);
3834       polynome _gcdmod(gcdmod(smod(pp,modulo),smod(qq,modulo),modulo));
3835       gen adjustcoeff=gcdfirstcoeff*invmod(_gcdmod.coord.front().value,modulo);
3836       _gcdmod=smod((_gcdmod * adjustcoeff), modulo) ;
3837       int m=_gcdmod.lexsorted_degree();
3838       if (!m){
3839 	p=pp*(plgcd/gcdlgcd);
3840 	q=qq*(qlgcd/gcdlgcd);
3841 	d=gcdlgcd;
3842 	return true;
3843       }
3844       // combine step
3845       if (m<gcddeg){ // previous prime was bad
3846 	gcddeg=m;
3847 	currentgcd=_gcdmod;
3848 	productmodulo=modulo;
3849       }
3850       else {
3851 	if (m==gcddeg){ // start combine
3852 	  if (productmodulo==gen(1)){ // no need to combine primes
3853 	    currentgcd=_gcdmod;
3854 	    productmodulo=modulo;
3855 	  }
3856 	  else {
3857 	    //  COUT << "Modulo:" << modulo << " " << _gcdmod << '\n';
3858 	    // COUT << "Old gcd:" << productmodulo << " " << currentgcd << '\n' ;
3859 	    currentgcd=ichinrem(_gcdmod,currentgcd,modulo,productmodulo);
3860 	    // COUT << "Combined to " << currentgcd << '\n';
3861 	    productmodulo=productmodulo*modulo;
3862 	  }
3863 	}
3864 	// m>gcddeg this prime is bad, just ignore
3865       }
3866       //      if (productmodulo>bound){
3867       d=smod(currentgcd,productmodulo);
3868       ppz(d);
3869       //if ( pp.TDivRem1(d,p_simp,rem) && rem.coord.empty() && qq.TDivRem1(d,q_simp,rem) && rem.coord.empty() ){
3870       if ( divrem1(pp,d,p_simp,rem) && rem.coord.empty() && divrem1(qq,d,q_simp,rem) && rem.coord.empty() ){
3871 	p=p_simp*(plgcd/gcdlgcd);
3872 	q=q_simp*(qlgcd/gcdlgcd);
3873 	d=d*gcdlgcd;
3874 	return true;
3875       }
3876       // }
3877     }
3878     return false;
3879   }
3880 
pzadic(const polynome & p,const gen & n)3881   polynome pzadic(const polynome &p,const gen & n){
3882     monomial_v v;
3883     index_t i;
3884     for (monomial_v::const_iterator it=p.coord.begin();it!=p.coord.end();++it){
3885       i.clear();
3886       i.push_back(0);
3887       for (index_t::const_iterator iti=it->index.begin();iti!=it->index.end();++iti)
3888 	i.push_back(*iti);
3889       gen k=it->value;
3890       for (int j=0;!is_zero(k);j++){
3891 	gen r=smod(k,n.re(0));
3892 	if (!is_zero(r)){
3893 	  i[0]=j;
3894 	  v.push_back(monomial<gen>(r,i));
3895 	}
3896 	k=iquo( (k-r),n.re(context0));
3897       }
3898     }
3899     // sort v
3900     polynome res(p.dim+1,v);
3901     res.tsort();
3902     return res;
3903   }
3904 
listmax(const polynome & p,gen & n)3905   bool listmax(const polynome &p,gen & n ){
3906     return Tlistmax<gen>(p,n);
3907   }
3908 
unext(const polynome & p,const gen & pmin,polynome & res)3909   bool unext(const polynome & p,const gen & pmin,polynome & res){
3910     res.dim=p.dim; res.coord.clear();
3911     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
3912     res.coord.reserve(itend-it);
3913     for (;it!=itend;++it){
3914       gen g=it->value;
3915       if (g.type==_FRAC)
3916 	return false;
3917       if (g.type==_EXT){
3918 	if (*(g._EXTptr+1)!=pmin)
3919 	  return false;
3920 	g=*g._EXTptr;
3921 	if (g.type==_VECT)
3922 	  g.subtype=_POLY1__VECT;
3923 	res.coord.push_back(monomial<gen>(g,it->index));
3924       }
3925       else
3926 	res.coord.push_back(*it);
3927     }
3928     return true;
3929   }
3930 
ext(polynome & res,const gen & pmin)3931   bool ext(polynome & res,const gen & pmin){
3932     vector< monomial<gen> >::iterator it=res.coord.begin(),itend=res.coord.end();
3933     for (;it!=itend;++it){
3934       gen g=ext_reduce(it->value,pmin);
3935       if (is_zero(g)) return false;
3936       it->value=g;
3937     }
3938     return true;
3939   }
3940 
ext(const polynome & p,const gen & pmin,polynome & res)3941   void ext(const polynome & p,const gen & pmin,polynome & res){
3942     res.dim=p.dim;
3943     res.coord.clear();
3944     res.coord.reserve(p.coord.size());
3945     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
3946     for (;it!=itend;++it){
3947       gen g=ext_reduce(it->value,pmin);
3948       if (is_zero(g))
3949 	continue;
3950       res.coord.push_back(monomial<gen>(g,it->index));
3951     }
3952   }
3953 
unmodularize(const polynome & p,polynome & res)3954   void unmodularize(const polynome & p,polynome & res){
3955     res.dim=p.dim;
3956     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
3957     res.coord.reserve(itend-it);
3958     for (;it!=itend;++it){
3959       if (it->value.type==_MOD)
3960 	res.coord.push_back(monomial<gen>(*it->value._MODptr,it->index));
3961       else
3962 	res.coord.push_back(monomial<gen>(it->value,it->index));
3963     }
3964   }
3965 
unmodularize(const polynome & p)3966   polynome unmodularize(const polynome & p){
3967     polynome res(p.dim);
3968     unmodularize(p,res);
3969     return res;
3970   }
3971 
modularize(polynome & d,const gen & m)3972   void modularize(polynome & d,const gen & m){
3973     vector< monomial<gen> >::iterator it=d.coord.begin(),itend=d.coord.end();
3974     for (;it!=itend;++it){
3975       if (it->value.type!=_USER)
3976 	it->value=makemod(it->value,m);
3977     }
3978   }
3979 
3980   // Find indexes of p such that p is constant, answer is in i
has_constant_variables(const polynome & p,index_t & i)3981   static void has_constant_variables(const polynome & p,index_t & i){
3982     i=index_t(p.dim,0);
3983     for (int j=0;j<p.dim;++j){
3984       i[j]=j;
3985     }
3986     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
3987     index_t::iterator iit,iitend;
3988     for (;it!=itend && !i.empty();++it){
3989       index_t::const_iterator j=it->index.begin();
3990       iit=i.begin(); iitend=i.end();
3991       for (;iit!=iitend;){
3992 	if (*(j+*iit)){ // non-0 power in monomial
3993 	  i.erase(iit);
3994 	  iit=i.begin();
3995 	  iitend=i.end();
3996 	}
3997 	else
3998 	  ++iit;
3999       }
4000     }
4001   }
4002 
4003   // p assumed to be constant wrt variables in pi
4004   // vi is a vector of degree
extract_monomials(const polynome & p,const index_t & pi,vectpoly & vp)4005   static int extract_monomials(const polynome &p,const index_t & pi,vectpoly & vp){
4006     index_t pdeg=p.degree();
4007     // find largest degree of p with respect to these variables
4008     int s=int(pi.size()),ans=1;
4009     index_t v(s+1);
4010     int i=0;
4011     for (;i<s;++i){
4012       if (ans>1000) // FIXME what's the right size??
4013 	return i;
4014       v[i]=pdeg[pi[i]]+1;
4015       ans=ans*v[i];
4016     }
4017     if (ans>10000)
4018       return -1;
4019     vp=vectpoly(ans,polynome(p.dim-s));
4020     if (ans==1)
4021       vp[0].coord.reserve(p.coord.size());
4022     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
4023     index_t::const_iterator piitbeg=pi.begin(),piit,piitend=pi.end(),vitbeg=v.begin(),vit,iti;
4024     index_t::iterator iit;
4025     int vp_pos;
4026     for (;it!=itend;++it){
4027       index_m i(p.dim-s);
4028       piit=piitbeg;
4029       vit=vitbeg;
4030       iit=i.begin();
4031       iti=it->index.begin();
4032       vp_pos=0;
4033       // construct new index without constant variables
4034       // and find value of index inside vp
4035       // iti index in current monomial of p, piit index in list of variables (p or q cst), vit index in v
4036       for (int j=0;j!=p.dim;++iti,++j){
4037 	if (piit!=piitend && j==*piit){
4038 	  ++piit;
4039 	  vp_pos=vp_pos*(*vit)+(*iti);
4040 	  ++vit;
4041 	}
4042 	else {
4043 	  *iit=*iti;
4044 	  ++iit;
4045 	}
4046       }
4047       vp[vp_pos].coord.push_back(monomial<gen>(it->value,i));
4048     }
4049     return 0;
4050   }
4051 
has_constant_variables_gcd(const polynome & p,const polynome & q,polynome & d)4052   static bool has_constant_variables_gcd(const polynome & p,const polynome & q,polynome & d){
4053     if (q.coord.empty()){
4054       d=p;
4055       return true;
4056     }
4057     if (p.coord.empty()){
4058       d=q;
4059       return true;
4060     }
4061     index_t pi,qi;
4062     has_constant_variables(p,pi);
4063     has_constant_variables(q,qi);
4064     // merge pi and qi
4065     index_t::iterator qit=qi.begin(),qitend=qi.end();
4066     for (;qit!=qitend;++qit){
4067       if (!equalposcomp(pi,*qit))
4068 	pi.push_back(*qit);
4069     }
4070     if (pi.empty())
4071       return false;
4072     int s=int(pi.size());
4073     if (s==p.dim){
4074       gen n=gcd(Tcontent<gen>(p),Tcontent<gen>(q),context0);
4075       d=polynome(monomial<gen>(n,p.dim));
4076       return true;
4077     }
4078     sort(pi.begin(),pi.end());
4079     // p or q is constant with respect to at least one variable
4080     // make a vector of polynomial from p and q
4081     vectpoly vp,vq;
4082     int i;
4083     if ( (i=extract_monomials(p,pi,vp)) ){
4084       if (i<0)
4085 	return false;
4086       pi=index_t(pi.begin(),pi.begin()+i);
4087       i=extract_monomials(p,pi,vp);
4088       if (i<0)
4089 	return false;
4090     }
4091     if ( (i=extract_monomials(q,pi,vq)) ){
4092       if (i<0)
4093 	return false;
4094       pi=index_t(pi.begin(),pi.begin()+i);
4095       extract_monomials(p,pi,vp);
4096       i=extract_monomials(q,pi,vq);
4097       if (i<0)
4098 	return false;
4099     }
4100     // find gcd of polys in vp and vq
4101     vectpoly::const_iterator it=vp.begin(),itend=vp.end(),jt=vq.begin(),jtend=vq.end();
4102     d=*jt;
4103     for (++jt;!is_one(d) && it!=itend;++it)
4104       d=gcd(d,*it);
4105     for (;!is_one(d) && jt!=jtend;++jt)
4106       d=gcd(d,*jt);
4107     // reconstruct gcd of p and q
4108     vector< monomial<gen> >::iterator dt=d.coord.begin(),dtend=d.coord.end();
4109     index_t::const_iterator piitbeg=pi.begin(),piit,piitend=pi.end(),dtit;
4110     int j;
4111     for (;dt!=dtend;++dt){
4112       index_m newi;
4113       newi.reserve(p.dim);
4114       piit=piitbeg;
4115       dtit=dt->index.begin();
4116       for (j=0;j<p.dim;++j){
4117 	if (piit!=piitend && j==*piit){
4118 	  newi.push_back(0);
4119 	  ++piit;
4120 	}
4121 	else {
4122 	  newi.push_back(*dtit);
4123 	  ++dtit;
4124 	}
4125       }
4126       dt->index=newi;
4127     }
4128     d.dim=p.dim;
4129     return true;
4130   }
4131 
coefftype(const polynome & p,gen & coefft)4132   int coefftype(const polynome & p,gen & coefft){
4133     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
4134     int t=0;
4135     for (;it!=itend;++it){
4136       const unsigned char tmp=it->value.type;
4137       if (tmp==_INT_ || tmp==_ZINT)
4138 	continue;
4139       t=tmp;
4140       coefft=it->value;
4141       if (t==_USER)
4142 	return t;
4143       if (t==_MOD)
4144 	return t;
4145       if (t==_EXT)
4146 	return t;
4147     }
4148     return t;
4149   }
4150 
gcdheu(const polynome & p_orig,const index_t & p_deg,const polynome & q_orig,const index_t & q_deg,polynome & p_simp,gen & np_simp,polynome & q_simp,gen & nq_simp,polynome & d,gen & d_content,bool skip_test,bool compute_cofactors)4151   static bool gcdheu(const polynome &p_orig,const index_t & p_deg,const polynome &q_orig, const index_t & q_deg,polynome & p_simp, gen & np_simp, polynome & q_simp, gen & nq_simp, polynome & d, gen & d_content,bool skip_test,bool compute_cofactors){
4152     // COUT << "Entering gcdheu " << p.dim << '\n';
4153     if (debug_infolevel>=123456-p_orig.dim)
4154       CERR << "Gcdheu begin " << p_orig.dim << " " << CLOCK() << " " << p_deg << " " << p_orig.coord.size() << " " << q_deg << " " << q_orig.coord.size() << '\n';
4155     if (&p_orig!=&p_simp)
4156       p_simp=p_orig;
4157     if (&q_orig!=&q_simp)
4158       q_simp=q_orig;
4159     if (debug_infolevel>=123456-p_simp.dim)
4160       CERR << "Gcdheu end copy" << CLOCK() << '\n';
4161     // check if one coeff is a _MOD or _USER
4162     gen coefft,coeffqt;
4163     int pt=coefftype(p_simp,coefft),qt=coefftype(q_simp,coeffqt);
4164     if (pt>=_EXT && qt>=_EXT && pt!=qt){
4165 #ifndef NO_STDEXCEPT
4166       setsizeerr(gettext("Incompatible coeff type"));
4167 #endif
4168       return false;
4169     }
4170     if (pt<_EXT && qt>=_EXT){
4171       pt=qt;
4172       coefft=coeffqt;
4173     }
4174     // If p, q have modular coeff, use modular algo
4175     if (!pt){
4176       pt=qt;
4177       coefft=coeffqt;
4178     }
4179     d_content=1;
4180     if (pt==_MOD){
4181       gen m=*(coefft._MODptr+1);
4182       if (debug_infolevel)
4183 	CERR << "gcdmod begin " << CLOCK() << '\n';
4184       polynome pmod,qmod;
4185       unmodularize(p_simp,pmod);
4186       unmodularize(q_simp,qmod);
4187       d=gcdmod(pmod,qmod,m);
4188       if (debug_infolevel)
4189 	CERR << "gcdmod end " << CLOCK() << '\n';
4190       if (compute_cofactors){
4191 	polynome pmodd,qmodd,tmp;
4192 	divremmod(pmod,d,m,pmodd,tmp);
4193 	divremmod(qmod,d,m,qmodd,tmp);
4194 	// CERR << dmod << ":;\n" << pmodd << ":;\n" << qmodd << '\n';
4195 	p_simp=pmodd;
4196 	modularize(p_simp,m);
4197 	q_simp=qmodd;
4198 	modularize(q_simp,m);
4199       }
4200       modularize(d,m);
4201       return true;
4202     }
4203     if (pt==_USER){
4204       coefft._USERptr->polygcd(p_simp,q_simp,d);
4205       if (compute_cofactors){
4206 	p_simp=p_simp/d;
4207 	q_simp=q_simp/d;
4208       }
4209       return true;
4210     }
4211     // does not work for collect(( -az^2-3*az*cos(kt)^2+az-cos(kt)^2)*sqrt(2*cos(kt)^2+az^2+2*az*cos(kt)^2-1)*ax*ksx*sin(kt)+(az^2*cos(kt)^2+az*cos(kt)^2+az+2*cos(kt)^2-1)*sqrt(2*cos(kt)^2+az^2+2*az*cos(kt)^2-1)*ax*ktx*sin(kt)+(az^2+3*az*cos(kt)^2-az+cos(kt)^2)*sqrt(2*cos(kt)^2+az^2+2*az*cos(kt)^2-1)*ay*ksy*sin(kt)+(az^2+3*az*cos(kt)^2-az+cos(kt)^2)*sqrt(2*cos(kt)^2+az^2+2*az*cos(kt)^2-1)*ay*kty*sin(kt))
4212     // np_simp=(pt!=_EXT)?ppz(p_simp):1;
4213     // nq_simp=(qt!=_EXT)?ppz(q_simp):1;
4214     np_simp=ppz(p_simp);
4215     nq_simp=ppz(q_simp);
4216     if (debug_infolevel>=123456-p_simp.dim)
4217       CERR << "Gcdheu end ppz" << CLOCK() << " " << np_simp << " " << nq_simp << '\n';
4218     d_content=gcd(np_simp,nq_simp,context0);
4219     // type may have changed by ppz simplification, recheck
4220     if (!is_integer(np_simp))
4221       pt=coefftype(p_simp,coefft);
4222     if (!is_integer(nq_simp))
4223       qt=coefftype(q_simp,coeffqt);
4224     if (pt>=_EXT && qt>=_EXT && pt!=qt){
4225 #ifndef NO_STDEXCEPT
4226       setsizeerr(gettext("Incompatible coeff type"));
4227 #endif
4228       return false;
4229     }
4230     if (pt<_EXT && qt>=_EXT){
4231       pt=qt;
4232       coefft=coeffqt;
4233     }
4234     if (!pt){
4235       pt=qt;
4236       coefft=coeffqt;
4237     }
4238     if (qt==_POLY && pt<_POLY){
4239       pt=qt;
4240       coefft=coeffqt;
4241     }
4242     if (pt==_POLY){
4243       if (coefft.type!=_POLY){
4244 #ifndef NO_STDEXCEPT
4245 	setsizeerr();
4246 #endif
4247 	return false;
4248       }
4249       int innerdim=coefft._POLYptr->dim;
4250       polynome pmulti=unsplitmultivarpoly(p_simp,innerdim);
4251       polynome qmulti=unsplitmultivarpoly(q_simp,innerdim);
4252       d=gcd(pmulti,qmulti);
4253       d=splitmultivarpoly(d,innerdim);
4254       if (compute_cofactors){
4255 	p_simp=p_simp/d;
4256 	q_simp=q_simp/d;
4257       }
4258       return true;
4259     }
4260     if (Tis_constant(p_simp) || Tis_constant(q_simp)){
4261       if (debug_infolevel>=2)
4262 	CERR << "//Gcdheu p constant!" << '\n';
4263       d=polynome(plus_one,p_simp.dim);
4264       return true;
4265     }
4266     if (p_simp.dim==1 && !pt){
4267       // gcd in Z[X]
4268       return gcd_modular(p_simp,q_simp,d,p_simp,q_simp,compute_cofactors);
4269     }
4270     bool allowrational = (pt>=_POLY || qt>=_POLY) && (pt!=_EXT && qt!=_EXT);
4271     if (
4272 	!all_inf_equal(q_deg,p_deg)
4273 	// !(p_deg>q_deg)
4274 	){
4275       polynome quo(p_simp.dim);
4276       if (exactquotient(q_simp,p_simp,quo,allowrational)){
4277 	d=p_simp;
4278 	q_simp=quo;
4279 	p_simp=polynome(monomial<gen>(plus_one,0,p_simp.dim));
4280 	if (is_positive(-d.coord.front())){
4281 	  d=-d; p_simp=-p_simp; q_simp=-q_simp;
4282 	}
4283 	if ( debug_infolevel>=123456-p_simp.dim )
4284 	  CERR << "// End exact " << p_simp.dim << " " << CLOCK() << " " <<d.coord.size() << '\n';
4285 	return true;
4286       }
4287       if ( debug_infolevel>=123456-p_simp.dim )
4288 	CERR << "//Gcdheu exact division failed! " << CLOCK() << '\n';
4289       if (p_simp.coord.size()==1){
4290 	index_t i=index_gcd(p_simp.coord.front().index.iref(),q_simp.gcddeg());
4291 	d=polynome(monomial<gen>(plus_one,i));
4292 	if (i!=index_t(i.size())){
4293 	  i=-i;
4294 	  p_simp=p_simp.shift(i);
4295 	  q_simp=q_simp.shift(i);
4296 	}
4297 	return true;
4298       }
4299     }
4300     if (
4301 	!all_inf_equal(p_deg,q_deg)
4302 	//!(q_deg>p_deg)
4303 	) {
4304       polynome quo(p_simp.dim);
4305       if (exactquotient(p_simp,q_simp,quo,allowrational)){
4306 	d=q_simp;
4307 	p_simp=quo;
4308 	q_simp=polynome(monomial<gen>(plus_one,0,p_simp.dim));
4309 	if (is_positive(-d.coord.front())){
4310 	  d=-d; p_simp=-p_simp; q_simp=-q_simp;
4311 	}
4312 	if ( debug_infolevel>=123456-p_simp.dim )
4313 	  CERR << "//End exact " << p_simp.dim << " " << CLOCK() << " " << d.coord.size() << '\n';
4314 	return true;
4315       }
4316       if ( debug_infolevel>=123456-p_simp.dim )
4317 	CERR << "//Gcdheu exact division failed! " << CLOCK() << '\n';
4318       if (q_simp.coord.size()==1){
4319 	index_t i=index_gcd(q_simp.coord.front().index.iref(),p_simp.gcddeg());
4320 	d=polynome(monomial<gen>(plus_one,i));
4321 	if (i!=index_t(i.size())){
4322 	  i=-i;
4323 	  p_simp=p_simp.shift(i);
4324 	  q_simp=q_simp.shift(i);
4325 	}
4326 	return true;
4327       }
4328     }
4329     if (p_simp.lexsorted_degree()==0){
4330       if (debug_infolevel >= 20-p_simp.dim)
4331 	CERR << "Begin cst " << p_simp.dim << " " << CLOCK() << " " << d.coord.size() << '\n';
4332       if (q_simp.lexsorted_degree()==0){
4333 	d=gcd(p_simp.trunc1(),q_simp.trunc1()).untrunc1();
4334       }
4335       else {
4336 	d=p_simp;
4337 	Tlgcd<gen>(q_simp,d);
4338       }
4339       if (!is_one(d) && compute_cofactors){
4340 	p_simp=p_simp/d;
4341 	q_simp=q_simp/d;
4342       }
4343       if (debug_infolevel >= 20-p_simp.dim)
4344 	CERR << "End cst " << p_simp.dim << " " << CLOCK() << " " << d.coord.size() << '\n';
4345       return true;
4346     }
4347     if (q_simp.lexsorted_degree()==0){
4348       if (debug_infolevel >= 20-p_simp.dim)
4349 	CERR << "Begin cst " << p_simp.dim << " " << CLOCK() << " " << d.coord.size() << '\n';
4350       d=q_simp;
4351       Tlgcd<gen>(p_simp,d);
4352       if (!is_one(d) && compute_cofactors){
4353 	q_simp=q_simp/d;
4354 	p_simp=p_simp/d;
4355       }
4356       if (debug_infolevel >= 20-p_simp.dim)
4357 	CERR << "End cst " << p_simp.dim << " " << CLOCK() << " " << d.coord.size() << '\n';
4358       return true;
4359     }
4360     if (pt==_EXT){
4361       // FIXME then test for
4362       // m:=matrix(2,2,[1,1,i*(sqrt(a^2*b^2-4*a*b)+a*b)/(2*a),i*(-sqrt(a^2*b^2-4*a*b)+a*b)/(2*a)]); M:=simplify(trn(m)*m); egvl(M);
4363       int dim=p_simp.dim;
4364       vector< T_unsigned<gen,hashgcd_U> > p,q,g,pcof,qcof;
4365       index_t di(dim);
4366       std::vector<hashgcd_U> vars(dim);
4367       if (!convert(p_simp,q_simp,di,vars,p,q))
4368 	return false;
4369       if (!gcd_ext(p,q,g,pcof,qcof,vars,compute_cofactors,threads))
4370 	return false;
4371       if (debug_infolevel>1)
4372 	CERR << CLOCK()*1e-6 << " success gcd_ext" << '\n';
4373       convert_from<gen,hashgcd_U>(g,di,d);
4374       if (compute_cofactors){
4375 	convert_from<gen,hashgcd_U>(pcof,di,p_simp);
4376 	convert_from<gen,hashgcd_U>(qcof,di,q_simp);
4377       }
4378       // normalize gcd and cofactors
4379       gen firstd=evalf_double(d.coord.front().value,1,context0);
4380       if (firstd.type==_DOUBLE_ && is_positive(-firstd,context0)){
4381 	d *= -1;
4382 	if (compute_cofactors){
4383 	  p_simp *= -1;
4384 	  q_simp *= -1;
4385 	}
4386       }
4387       if (firstd.type==_CPLX && firstd._CPLXptr->type==_DOUBLE_ && (firstd._CPLXptr+1)->type==_DOUBLE_){
4388 	int arg=int(std::floor(std::atan2((firstd._CPLXptr+1)->_DOUBLE_val,firstd._CPLXptr->_DOUBLE_val)/(M_PI/2)));
4389 	if (arg!=0){
4390 	  gen mult=arg>0?(-cst_i):(arg==-1?cst_i:-1);
4391 	  d *= mult;
4392 	  if (compute_cofactors){
4393 	    p_simp *= mult;
4394 	    q_simp *= mult;
4395 	  }
4396 	}
4397       }
4398       return true;
4399     }
4400     int Dbdeg=giacmin(p_simp.lexsorted_degree(),q_simp.lexsorted_degree());
4401     bool est_reel=poly_is_real(p_simp) && poly_is_real(q_simp);    // FIXME: should check for extensions!
4402     if (debug_infolevel>=2)
4403       CERR << "//Gcdheu " << p_deg << " " << p_simp.coord.size() << " " << q_deg << " " << q_simp.coord.size() << '\n';
4404    // first try evaluation for quick trivial gcd
4405     if (!skip_test ){
4406       if (p_simp.dim>1) {
4407 	vecteur b(p_simp.dim-1);
4408 	polynome Fb(1),Gb(1),Db(1);
4409 	if (debug_infolevel >= 20-p_simp.dim)
4410 	  CERR << "// GCD eval dimension " << p_simp.dim << " " << CLOCK() << " " << p_deg << " " << p_simp.coord.size() << " " << q_deg << q_simp.coord.size() << " " << '\n';
4411 	gen essaimod=30013; // 30011; // mod 4 = 3
4412 	for (int essai=0;essai<2;++essai){
4413 	  if (essai)
4414 	    b=vranm(p_simp.dim-1,0,0); // find another random point
4415 	  // essaimod was est_reel?essaimod:0
4416 	  for (;!find_good_eval(p_simp,q_simp,Fb,Gb,b,debug_infolevel >= 20-p_simp.dim,essaimod);){
4417 	    for (;;){
4418 	      essaimod=nextprime(essaimod+1);
4419 	      if (is_one(smod(essaimod,4)))
4420 		break;
4421 	    }
4422 	  }
4423 #ifndef NO_STDEXCEPT
4424 	  try {
4425 #endif
4426 	    Db=gcdmod(Fb,Gb,essaimod);
4427 #ifndef NO_STDEXCEPT
4428 	  } catch (std::runtime_error & ){
4429 	    Db=gcd(Fb,Gb);
4430 	  }
4431 #endif
4432 	  Dbdeg=Db.lexsorted_degree();
4433 	  if (debug_infolevel >= 20-p_simp.dim)
4434 	    CERR << "// evaled GCD deg " << Dbdeg << '\n';
4435 	  if (!Dbdeg){
4436 	    d.coord.clear();
4437 	    Tcommonlgcd<gen>(p_simp,q_simp,d);
4438 	    if ( debug_infolevel >= 20-p_simp.dim )
4439 	      CERR << "end eval " << p_simp.dim << " " << CLOCK() << " " << d.coord.size() << '\n';
4440 	    if (compute_cofactors){
4441 	      p_simp=p_simp/d;
4442 	      q_simp=q_simp/d;
4443 	    }
4444 	    return true;
4445 	  }
4446 	  if (Dbdeg==p_simp.lexsorted_degree()){ // try p_simp/lgcd as gcd
4447 	    if ( debug_infolevel >= 20-p_simp.dim )
4448 	      CERR << "Trying p/lgcd(p) as gcd " << p_simp.dim << " " << CLOCK() << '\n';
4449 	    polynome p_simp_lgcd(Tlgcd<gen>(p_simp));
4450 	    if ( debug_infolevel >= 20-p_simp.dim )
4451 	      CERR << "lgcd(p) ok " << p_simp.dim << " " << CLOCK() << '\n';
4452 	    polynome p_simp_simp(p_simp.dim);
4453 	    if (!exactquotient(p_simp,p_simp_lgcd,p_simp_simp)) {
4454 #ifndef NO_STDEXCEPT
4455 	      setsizeerr(gettext("gausspol.cc/gcdheu"));
4456 #endif
4457 	      return false;
4458 	    }
4459 	    polynome quo(q_simp.dim);
4460 	    if (exactquotient(q_simp,p_simp_simp,quo)){
4461 	      if ( debug_infolevel >= 20-p_simp.dim )
4462 		CERR << "Success p/lgcd(p) as gcd " << p_simp.dim << " " << CLOCK() << '\n';
4463 	      polynome quo_lgcd(p_simp_lgcd);
4464 	      Tlgcd<gen>(quo,quo_lgcd);
4465 	      d=p_simp_simp*quo_lgcd;
4466 	      if (compute_cofactors){
4467 		p_simp=p_simp_lgcd/quo_lgcd;
4468 		q_simp=quo/quo_lgcd;
4469 	      }
4470 	      return true;
4471 	    }
4472 	    if ( debug_infolevel >= 20-p_simp.dim )
4473 	      CERR << "Failed p/lgcd(p) as gcd " << p_simp.dim << " " << CLOCK() << '\n';
4474 	  }
4475 	  if (Dbdeg==q_simp.lexsorted_degree()){ // try p_simp/lgcd as gcd
4476 	    if ( debug_infolevel >= 20-p_simp.dim )
4477 	      CERR << "Trying q/lgcd(q) as gcd " << p_simp.dim << " " << CLOCK() << '\n';
4478 	    polynome q_simp_lgcd(Tlgcd<gen>(q_simp));
4479 	    if ( debug_infolevel >= 20-p_simp.dim )
4480 	      CERR << "lgcd(q) ok " << p_simp.dim << " " << CLOCK() << '\n';
4481 	    polynome q_simp_simp(q_simp.dim);
4482 	    if (!exactquotient(q_simp,q_simp_lgcd,q_simp_simp)){
4483 #ifndef NO_STDEXCEPT
4484 	      setsizeerr(gettext("gausspol.cc/gcdheu"));
4485 #endif
4486 	      return false;
4487 	    }
4488 	    polynome quo(p_simp.dim);
4489 	    if (exactquotient(p_simp,q_simp_simp,quo)){
4490 	      if ( debug_infolevel >= 20-p_simp.dim )
4491 		CERR << "Success q/lgcd(q) as gcd " << p_simp.dim << " " << CLOCK() << '\n';
4492 	      polynome quo_lgcd(q_simp_lgcd);
4493 	      Tlgcd<gen>(quo,quo_lgcd);
4494 	      d=q_simp_simp*quo_lgcd;
4495 	      if (compute_cofactors){
4496 		q_simp=q_simp_lgcd/quo_lgcd;
4497 		p_simp=quo/quo_lgcd;
4498 	      }
4499 	      return true;
4500 	    }
4501 	    if ( debug_infolevel >= 20-p_simp.dim )
4502 	      CERR << "Failed q/lgcd(q) as gcd " << p_simp.dim << " " << CLOCK() << '\n';
4503 	  }
4504 	}
4505       }
4506     }
4507     // now work on p_simp and q_simp
4508     if (!p_simp.dim){
4509       d=polynome(gen(1),0);
4510       return true;
4511     }
4512     gen np,nq,n;
4513     if (!listmax(p_simp,np)){
4514       return false;
4515     }
4516     if (!listmax(q_simp,nq)){
4517       return false;
4518     }
4519     if (p_simp.dim==1){ // integer modular try, was p_simp.dim==1 && est_reel
4520       environment * env= new environment;
4521       bool avoid_it=false;
4522       dense_POLY1 pp,qq;
4523 #ifndef NO_STDEXCEPT
4524       try {
4525 #endif
4526 	pp=modularize(p_simp,0,env);
4527 	qq=modularize(q_simp,0,env);
4528 	if (is_undef(pp) || is_undef(qq))
4529 	  avoid_it=true;
4530 #ifndef NO_STDEXCEPT
4531       }
4532       catch (std::runtime_error & ){
4533 	avoid_it=true;
4534       }
4535 #endif
4536       env->moduloon = true;
4537       env->modulo=1001;
4538       env->pn=env->modulo;
4539       env->complexe=!est_reel;
4540       for (int essai=0;essai<2 && !avoid_it;++essai){
4541 	env->modulo=nextprime(env->modulo+2);
4542 	while ( !is_one(smod(env->modulo,4)) || !is_one(gcd(gcd(env->modulo,pp.front(),context0),qq.front(),context0)) )
4543 	  env->modulo=nextprime(env->modulo+2);
4544 	modpoly _gcdmod;
4545 	gcdmodpoly(pp,qq,env,_gcdmod);
4546 	if (is_undef(_gcdmod))
4547 	  return false;
4548 	Dbdeg=giacmin(Dbdeg,int(_gcdmod.size())-1);
4549 	if (!Dbdeg)
4550 	  break;
4551       }
4552       delete env;
4553       if (!Dbdeg){
4554 	d=polynome(gen(1),p_simp.dim);
4555 	return true;
4556       }
4557     }
4558     polynome p1(p_simp.dim),q1(p_simp.dim),r1(p_simp.dim),r2(p_simp.dim);
4559     gen n_2(2),n_73794(73794),n_27011(27011);
4560     if (is_greater(nq,np,context0))
4561       n=n_2*nq+n_2;
4562     else
4563       n=n_2*np+n_2;
4564     // PSR if gcd has a large degree, modular if low degree, else try heugcd
4565     // PSR complexity is proportionnal to
4566     // #iteration*deg_var_n*(total_deg_other_vars*#iteration)^(2*#other_var)
4567     // MODGCD to product of all (part_deg_of_gcd+1+part_deg_of_gcd_lcoeff)
4568     int maxpqdeg0=giacmax(p_simp.lexsorted_degree(),q_simp.lexsorted_degree());
4569     int minpqdeg0=giacmin(p_simp.lexsorted_degree(),q_simp.lexsorted_degree());
4570     index_t maxpqdeg(p_simp.dim);
4571     double sparsenessp=double(p_simp.coord.size()),sparsenessq=double(q_simp.coord.size());
4572     for (int i=0;i<p_simp.dim;++i){
4573       maxpqdeg[i]=giacmax(p_deg[i],q_deg[i]);
4574       sparsenessp /= (p_deg[i]+i+1);
4575       sparsenessp *= (i+1);
4576       sparsenessq /= (q_deg[i]+i+1);
4577       sparsenessq *= (i+1);
4578     }
4579     double heugcddigits=1.0,maxmodop=1.0,minmodop=1.0;
4580     int total_deg_other_var=-maxpqdeg[0];
4581     for (int i=0;i<p_simp.dim;++i){
4582       heugcddigits *= maxpqdeg[i] ;
4583       minmodop *= Dbdeg+1; // approximation!!! should be partial degree[gcd]
4584       maxmodop *= giacmin(p_deg[i],q_deg[i])+1+p_deg[i]+q_deg[i];
4585       total_deg_other_var += maxpqdeg[i];
4586     }
4587     double psrstep=minpqdeg0-Dbdeg;
4588     double psrgcdop=std::pow(psrstep,2*(p_simp.dim-1))*(p_simp.coord.size()*q_simp.coord.size())/minpqdeg0, modop=std::sqrt(minmodop*maxmodop)/10,heuop=heugcddigits*heugcddigits/10.0;
4589     double minop=psrgcdop; if (psrgcdop>heuop) minop=heuop; if (minop>modop) minop=modop;
4590     if (debug_infolevel)
4591       CERR << "Psr " << psrgcdop << ", Mod " << modop << ", Heu " << heuop << ", Min" << minop << '\n';
4592     if (modop<minop) minop=modop; // was if (est_reel && modop<minop)
4593     if (debug_infolevel){
4594       if (p_simp.dim==1)
4595 	CERR << "GCD dim 1, n=" << n << " maxpqdeg0 " << maxpqdeg0 << "(" << maxpqdeg << ")" << '\n';
4596       else
4597 	CERR << "GCD dim " << p_simp.dim << " degree " << Dbdeg << " psrgcdop " << psrgcdop << " heuop " << heuop << " modgcdop " << minmodop << "," << maxmodop << '\n';
4598     }
4599     if (!skip_test){
4600       // int dd=p_simp.dim*p.lexsorted_degree();
4601       // first try ezgcd then modgcd
4602       if ( // false && // uncomment to cancel EZGCD
4603 	  (sparsenessp<0.3 || sparsenessq<0.3 ) && psrgcdop> modop &&
4604 	  (p_simp.dim>3) // && (Dbdeg<=maxpqdeg0/4+1)
4605 	  && ezgcd(p_simp,q_simp,d,true,true,0,minop)){
4606 	if (debug_infolevel)
4607 	  COUT << "// Used EZ gcd " << '\n';
4608 	if (compute_cofactors){
4609 	  q_simp=q_simp/d;
4610 	  p_simp=p_simp/d;
4611 	}
4612 	return true;
4613       }
4614       if (//false &&
4615 	  p_simp.dim>1 && psrgcdop< modop && psrgcdop < heuop ){
4616 	d=gcdpsr(p_simp,q_simp,Dbdeg);
4617 	if (compute_cofactors){
4618 	  q_simp=q_simp/d;
4619 	  p_simp=p_simp/d;
4620 	}
4621 	return true;
4622       }
4623 #ifndef NSPIRE
4624       if (//true ||
4625 	  modop < heuop
4626 	  ){ // was  if ( modop < heuop && est_reel)
4627 	if (debug_infolevel)
4628 	  COUT << "// " << CLOCK() << " Using modular gcd " << '\n';
4629 	bool res=gcd_modular(p_simp,q_simp,d,p_simp,q_simp,compute_cofactors);
4630 	if (debug_infolevel)
4631 	  COUT << "// " << CLOCK() << " End modular gcd " << '\n';
4632 	return res;
4633       }
4634 #endif
4635     }
4636     if (debug_infolevel)
4637       COUT << "// Using Heu gcd " << '\n';
4638     int max_try=0;
4639     for (; max_try<GCDHEU_MAXTRY;max_try++){
4640       polynome pn(p_simp(n));
4641       // COUT << p_simp << " pn:" << pn << " n=" << n << '\n';
4642       polynome qn(q_simp(n));
4643       // NEW CODE
4644       if (skip_test){
4645 	polynome pntmp,qntmp;
4646 	gen pnsimp,qnsimp,dtmp;
4647 	if (!gcdheu(pn,qn,pntmp,pnsimp,qntmp,qnsimp,d,dtmp,true,compute_cofactors)){
4648 	  return false;
4649 	}
4650 	d=pzadic(d*dtmp,n);
4651       }
4652       else {
4653       // OLD CODE
4654 	d=gcd(pn,qn);
4655 	d=pzadic(d,n);
4656       }
4657       // END MODIFICATIONS
4658       ppz(d);
4659       if (!d.coord.empty()){
4660 	gen tmp=d.coord.front().value;
4661 	if (is_zero(re(tmp,context0))){ // checked
4662 	  d=cst_i*d;
4663 	  tmp=cst_i*tmp;
4664 	}
4665 	if (is_positive(-tmp,context0)) // checked
4666 	  d=-d;
4667       }
4668       //      COUT << "(ppz) d=" << d << '\n';
4669       // COUT << "p_simp" << p_simp << '\n' << "q_simp" << q_simp << '\n';
4670       //if ( divrem(p_simp,d,p1,r1,false) && (r1.coord.size()==0) && divrem(q_simp,d,q1,r2,false) && (r2.coord.size()==0) ){
4671       if ( p_simp.TDivRem1(d,p1,r1) && (r1.coord.size()==0) && q_simp.TDivRem1(d,q1,r2) && (r2.coord.size()==0) ){
4672 	//	COUT << "p_simp/d" << p1 << "q_simp/d" << q1 << '\n';
4673 	p_simp=p1;
4674 	q_simp=q1;
4675 	// COUT << "gcdheu success " << max_try << '\n';
4676 	if (debug_infolevel >= 20-p_simp.dim)
4677 	  CERR << "end gcdheu " << p_simp.dim << " " << CLOCK() << " " << d.coord.size() << '\n';
4678 	return true;
4679       }
4680       n=iquo(n*n_73794,n_27011);
4681     }
4682     // COUT << "gcdheu failure" << '\n';
4683     return false;
4684   }
4685 
gcdheu(const polynome & p_orig,const polynome & q_orig,polynome & p_simp,gen & np_simp,polynome & q_simp,gen & nq_simp,polynome & d,gen & d_content,bool skip_test,bool compute_cofactors)4686   bool gcdheu(const polynome &p_orig,const polynome &q_orig, polynome & p_simp, gen & np_simp, polynome & q_simp, gen & nq_simp, polynome & d, gen & d_content,bool skip_test,bool compute_cofactors){
4687     index_t pdeg=p_orig.degree(),qdeg=q_orig.degree();
4688     return gcdheu(p_orig,pdeg,q_orig,qdeg,p_simp,np_simp,q_simp,nq_simp,d,d_content,skip_test,compute_cofactors);
4689   }
4690 
gcdpsr(const polynome & p,const polynome & q,int gcddeg)4691   polynome gcdpsr(const polynome &p,const polynome &q,int gcddeg){
4692     if (has_num_coeff(p) || has_num_coeff(q))
4693       return polynome( monomial<gen>(1,p.dim));
4694     if (debug_infolevel)
4695       COUT << "// Using PSR gcd " << '\n';
4696     if (!gcddeg && p.dim>1){ // find probable degree
4697       vecteur b(p.dim-1);
4698       polynome Fb(1),Gb(1),Db(1);
4699       for (int essai=0;essai<2;++essai){
4700 	if (essai)
4701 	  b=vranm(p.dim-1,0,0); // find another random point
4702 	find_good_eval(p,q,Fb,Gb,b,debug_infolevel >= 20-p.dim);
4703 	Db=gcd(Fb,Gb);
4704 	int Dbdeg=Db.lexsorted_degree();
4705 	if (!Dbdeg)
4706 	  return gcd(Tlgcd(p),Tlgcd(q));
4707 	if (!gcddeg)
4708 	  gcddeg=Dbdeg;
4709 	else
4710 	  gcddeg=giacmin(Dbdeg,gcddeg);
4711       }
4712     }
4713     return Tgcdpsr<gen>(p,q,gcddeg);
4714   }
4715 
findabcdelta(const polynome & p,polynome & a,polynome & b,polynome & c,polynome & delta)4716   bool findabcdelta(const polynome & p,polynome & a,polynome &b,polynome & c,polynome & delta){
4717     if (p.lexsorted_degree()!=2)
4718       return false;
4719     monomial_v::const_iterator it=p.coord.begin(),itend=p.coord.end();
4720     a=Tnextcoeff<gen>(it,itend);
4721     if (it==itend){
4722       b=polynome(a.dim);
4723       c=polynome(a.dim);
4724       delta=polynome(a.dim);
4725       return true;
4726     }
4727     if (it->index.front()==1)
4728       b=Tnextcoeff<gen>(it,itend);
4729     else
4730       b=polynome(a.dim);
4731     if (it==itend)
4732       c=polynome(a.dim);
4733     else
4734       c=Tnextcoeff<gen>(it,itend);
4735     delta=b*b-a*c*gen(4);
4736     return (it==itend);
4737   }
4738 
findde(const polynome & p,polynome & d,polynome & e)4739   bool findde(const polynome & p,polynome & d,polynome &e){
4740     if (p.coord.empty()){
4741       d=p;
4742       e=p;
4743       return true;
4744     }
4745     int n=p.lexsorted_degree();
4746     if (n>1)
4747       return false;
4748     monomial_v::const_iterator it=p.coord.begin(),itend=p.coord.end();
4749     if (!n){
4750       e=Tnextcoeff<gen>(it,itend);
4751       d=polynome(e.dim);
4752       return(it==itend);
4753     }
4754     d=Tnextcoeff<gen>(it,itend);
4755     if (it==itend)
4756       e=polynome(d.dim);
4757     else
4758       e=Tnextcoeff<gen>(it,itend);
4759     return (it==itend);
4760   }
4761 
total_degree(const polynome & p)4762   int total_degree(const polynome & p){
4763     int res=0,deg;
4764     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
4765     for (;it!=itend;++it){
4766       deg=int(it->index.total_degree());
4767       if (deg>res)
4768 	res=deg;
4769     }
4770     return res;
4771   }
4772 
4773   // evaluate all vars but the j-th to 0
peval0(const polynome & p,int j,int & total_deg)4774   static gen peval0(const polynome & p,int j,int & total_deg){
4775     if (!j){
4776       vecteur v(p.dim-1);
4777       total_deg=total_degree(Tfirstcoeff<gen>(p).degree());
4778       return peval(p,v,0);
4779     }
4780     vecteur res;
4781     total_deg=0;
4782     int s=0,smax=0,n=p.dim,total;
4783     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
4784     int i,k=0;
4785     index_t::const_iterator itit;
4786     bool add;
4787     for (;it!=itend;++it){
4788       itit=it->index.begin();
4789       add=true;
4790       for (i=0,total=0;i<n;++i,++itit){
4791 	total += *itit;
4792 	if (i==j)
4793 	  k=*itit;
4794 	else {
4795 	  if (*itit)
4796 	    add=false;
4797 	}
4798       }
4799       if (add) {
4800 	if (k<s)
4801 	  res[k] = res[k]+it->value;
4802 	else {
4803 	  for (;s<k;++s)
4804 	    res.push_back(0);
4805 	  res.push_back(it->value);
4806 	  ++s;
4807 	}
4808       }
4809       if (k>smax){
4810 	total_deg=total-k;
4811 	smax=k;
4812       }
4813       if (k==smax)
4814 	total_deg=giacmax(total_deg,total-k);
4815     }
4816     reverse(res.begin(),res.end());
4817     return trim(res,0);
4818   }
4819 
dividedegrees(polynome & p,int var,int d)4820   static void dividedegrees(polynome & p,int var,int d) {
4821     if (d==1) return;
4822     std::vector< monomial<gen> >::iterator it=p.coord.begin(),it_end=p.coord.end();
4823     for (;it!=it_end;++it){
4824       index_t i=it->index.iref();
4825       i[var] /= d;
4826       it->index=i;
4827     }
4828   }
4829 
4830   // return gcd of exponents in p and q for variable number var
xn2x(const polynome & p,const polynome & q,int var)4831   static int xn2x(const polynome & p,const polynome & q,int var){
4832     vector< monomial<gen> >::const_iterator It=p.coord.begin(),Itend=p.coord.end();
4833     int l=0;
4834     for (;It!=Itend;++It){
4835       const index_t &i=It->index.iref();
4836       l=gcd(l,i[var]);
4837       if (l==1)
4838 	return 1;
4839     }
4840     It=q.coord.begin();Itend=q.coord.end();
4841     for (;It!=Itend;++It){
4842       const index_t &i=It->index.iref();
4843       l=gcd(l,i[var]);
4844       if (l==1)
4845 	return 1;
4846     }
4847     return l;
4848   }
4849 
xn2x(polynome & p,polynome & q,vector<int> & gcd_index)4850   static bool xn2x(polynome &p,polynome & q,vector<int> & gcd_index){
4851     gcd_index=vector<int>(p.dim,1);
4852     bool ans=false;
4853     for (int i=0;i<p.dim;++i){
4854       int res=xn2x(p,q,i);
4855       ans = ans | (res>1);
4856       gcd_index[i] = res;
4857       if (res){
4858 	dividedegrees(p,i,res);
4859 	dividedegrees(q,i,res);
4860       }
4861     }
4862     return ans;
4863   }
4864 
xn2x(const polynome & p,const polynome & q)4865   static bool xn2x(const polynome &p,const polynome & q){
4866     for (int i=0;i<p.dim;++i){
4867       int res=xn2x(p,q,i);
4868       if (res>1)
4869 	return true;
4870     }
4871     return false;
4872   }
4873 
multiplydegrees(polynome & p,int var,int d)4874   static void multiplydegrees(polynome & p,int var,int d) {
4875     if (d==1) return;
4876     std::vector< monomial<gen> >::iterator it=p.coord.begin(),it_end=p.coord.end();
4877     for (;it!=it_end;++it){
4878       index_t i=it->index.iref();
4879       i[var] *= d;
4880       it->index=i;
4881     }
4882   }
4883 
x2xn(polynome & p,vector<int> & gcd_index)4884   static void x2xn(polynome &p,vector<int> & gcd_index){
4885     for (int i=0;i<p.dim;++i){
4886       multiplydegrees(p,i,gcd_index[i]);
4887     }
4888   }
4889 
exchange_variables(polynome & p,const index_t & pdeg,polynome & q,const index_t & qdeg,std::vector<int> & permutation)4890   static bool exchange_variables(polynome & p,const index_t & pdeg,polynome & q,const index_t & qdeg,std::vector<int> & permutation){
4891     if (p.dim<2)
4892       return false;
4893     int pd=pdeg.front(),qd=qdeg.front(),res=giacmin(pd,qd),pos=0,tmp;
4894     // Find first lowest degree position
4895     vector<int> vpos(1,0);
4896     for (int j=1;j<p.dim;++j){
4897       if ( (tmp=giacmin(pdeg[j],qdeg[j])) <res){
4898 	res=tmp;
4899 	vpos=vector<int>(1,j);
4900       }
4901       if (tmp==res)
4902 	vpos.push_back(j);
4903     }
4904     int s=int(vpos.size());
4905     // Same lowest degree, eval p at 0...0 and compare
4906     // (for ezgcd to find good eval: peval at zero must be non 0
4907     // and the lcoeff must be as small as possible)
4908     pos=vpos[0];
4909     if (s>1){
4910       int plcoeff,qlcoeff;
4911       gen p0=peval0(p,pos,plcoeff);
4912       gen q0=peval0(q,pos,qlcoeff);
4913       for (int j=1;j<s;++j){
4914 	if (!is_zero(p0) && !is_zero(q0) && plcoeff==0)
4915 	  break;
4916 	int ptmplcoeff,qtmplcoeff;
4917 	gen p0tmp(peval0(p,vpos[j],ptmplcoeff)),q0tmp(peval0(q,vpos[j],qtmplcoeff));
4918 	if ( is_zero(p0tmp) || is_zero(q0tmp) )
4919 	  continue;
4920 	if ( is_zero(p0) || is_zero(q0) || (ptmplcoeff<plcoeff) ){
4921 	  p0=p0tmp;
4922 	  q0=q0tmp;
4923 	  plcoeff=ptmplcoeff;
4924 	  pos=vpos[j];
4925 	}
4926       }
4927     }
4928     if (!pos)
4929       return false;
4930     if (debug_infolevel >= 20-p.dim)
4931       CERR << "Exchange " << CLOCK() << " " << p.dim << " " << p.degree() << " " << p.coord.size() << " " << q.degree() << " " << q.coord.size() << '\n';
4932     permutation=transposition(0,pos,p.dim);
4933     p.reorder(permutation);
4934     q.reorder(permutation);
4935     return true;
4936   }
4937 
lcmdeno(const polynome & p,gen & res)4938   void lcmdeno(const polynome & p, gen & res){
4939     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
4940     for (;it!=itend;++it){
4941       if (it->value.type!=_FRAC)
4942 	continue;
4943       gen tmp=it->value,tmpden=1;
4944       while (tmp.type==_FRAC){
4945 	tmpden=tmpden*tmp._FRACptr->den;
4946 	tmp=tmp._FRACptr->num;
4947       }
4948       res=lcm(tmpden,res);
4949     }
4950   }
4951 
simplify_gcdpart(polynome & p,polynome & q,polynome & p_gcd,bool ckxn2x)4952   void simplify_gcdpart(polynome & p,polynome & q,polynome & p_gcd,bool ckxn2x){
4953     vector<int> gcd_index;
4954     if (ckxn2x && xn2x(p,q,gcd_index)){
4955       simplify_gcdpart(p,q,p_gcd,false);
4956       x2xn(p_gcd,gcd_index);
4957       x2xn(p,gcd_index);
4958       x2xn(q,gcd_index);
4959       return;
4960     }
4961     polynome p_orig(p);
4962     polynome q_orig(q);
4963     p_gcd.coord.clear();
4964     std::vector<int> permutation;
4965     index_t pdeg=p.degree(),qdeg=q.degree();
4966     bool exchanged=exchange_variables(p_orig,pdeg,q_orig,qdeg,permutation);
4967     gen d_content=1,np_simp=1,nq_simp=1;
4968     if (gcdheu(p_orig,pdeg,q_orig,qdeg,p,np_simp,q,nq_simp,p_gcd,d_content,false,true)){
4969       p=p*rdiv(np_simp,d_content,context0);
4970       q=q*rdiv(nq_simp,d_content,context0);
4971       if (exchanged){
4972 	p.reorder(permutation);
4973 	q.reorder(permutation);
4974 	p_gcd.reorder(permutation);
4975 	if (!p_gcd.coord.empty() && is_strictly_positive(-p_gcd.coord.front().value,context0)){
4976 	  p_gcd=-p_gcd;
4977 	  p=-p;
4978 	  q=-q;
4979 	}
4980       }
4981       p_gcd=p_gcd*d_content;
4982       return ;
4983     }
4984     p_gcd=gcdpsr(p_orig,q_orig);
4985     polynome tmprem(p_gcd.dim);
4986     p_orig.TDivRem1(p_gcd,p,tmprem,true);
4987     q_orig.TDivRem1(p_gcd,q,tmprem,true);
4988     // If alg. extensions are involved, p and q may now contain fractions
4989     gen tmpmult(plus_one);
4990     lcmdeno(p,tmpmult);
4991     lcmdeno(q,tmpmult);
4992     p=p*tmpmult;
4993     q=q*tmpmult;
4994     if (exchanged){
4995       p.reorder(permutation);
4996       q.reorder(permutation);
4997       p_gcd.reorder(permutation);
4998     }
4999     p_gcd=inv(tmpmult,context0)*p_gcd;
5000     return ;
5001   }
5002 
simplify(polynome & p,polynome & q,polynome & p_gcd)5003   void simplify(polynome & p,polynome & q,polynome & p_gcd){
5004     if (is_one(q)){
5005       p_gcd=q;
5006       return;
5007     }
5008     if (is_one(p)){
5009       p_gcd=p;
5010       return ;
5011     }
5012     if (q.coord.empty()){
5013       p_gcd=polynome(gen(1),p.dim);
5014       swap(p_gcd.coord,p.coord);
5015       return ;
5016     }
5017     if (p.coord.empty()){
5018       p_gcd=polynome(gen(1),p.dim);
5019       swap(p_gcd.coord,q.coord);
5020       return ;
5021     }
5022     if (!p.dim){
5023       gen p0=p.coord.front().value,q0=q.coord.front().value;
5024       gen tmp=simplify(p0,q0);
5025       p=polynome(p0,0);
5026       q=polynome(q0,0);
5027       p_gcd=polynome(tmp,0);
5028       return;
5029     }
5030     if (p==q){
5031       p_gcd=polynome(gen(1),p.dim);
5032       swap(p.coord,p_gcd.coord);
5033       q=p;
5034       return;
5035     }
5036     if (has_constant_variables_gcd(p,q,p_gcd)){
5037       polynome temp(p.dim);
5038       exactquotient(p,p_gcd,temp);
5039       swap(p.coord,temp.coord);
5040       exactquotient(q,p_gcd,temp);
5041       swap(q.coord,temp.coord);
5042       return ;
5043     }
5044     index_t pback=p.coord.back().index.iref(),qback=q.coord.back().index.iref();
5045     if (!is_zero(pback))
5046       pback=p.gcddeg();
5047     if (!is_zero(qback))
5048       qback=q.gcddeg();
5049     if (!is_zero(pback) || !is_zero(qback)){
5050       index_t dback=index_gcd(pback,qback);
5051       if (!is_zero(pback))
5052 	p=p.shift(-pback);
5053       if (!is_zero(qback))
5054 	q=q.shift(-qback);
5055       simplify_gcdpart(p,q,p_gcd,true);
5056       if (!is_zero(dback)){
5057 	p_gcd=p_gcd.shift(dback);
5058 	pback = pback-dback;
5059 	qback = qback-dback;
5060       }
5061       if (!is_zero(pback))
5062 	p=p.shift(pback);
5063       if (!is_zero(qback))
5064 	q=q.shift(qback);
5065       return;
5066     }
5067     simplify_gcdpart(p,q,p_gcd,true /* ckxn2x */);
5068   }
5069 
simplify(polynome & p,polynome & q)5070   polynome simplify(polynome &p,polynome &q){
5071     polynome p_gcd(p.dim);
5072     simplify(p,q,p_gcd);
5073     return p_gcd;
5074   }
5075 
gcd_gcdpart(const polynome & p,const polynome & q,polynome & d,bool ckxn2x)5076   void gcd_gcdpart(const polynome & p,const polynome & q,polynome & d,bool ckxn2x){
5077     if (ckxn2x && xn2x(p,q)){
5078       polynome p_(p),q_(q);
5079       vector<int> gcd_index;
5080       xn2x(p_,q_,gcd_index);
5081       gcd_gcdpart(p_,q_,d,false);
5082       x2xn(d,gcd_index);
5083       return;
5084     }
5085     polynome p_simp(p.dim),q_simp(p.dim);
5086     index_t pdeg=p.degree(),qdeg=q.degree();
5087     gen d_content,np_simp,nq_simp;
5088     if (p.coord.front().value.type==_MOD && gcdheu(p,pdeg,q,qdeg,p_simp,np_simp,q_simp,nq_simp,d,d_content,false,false) ){
5089       d *= d_content;
5090       return ;
5091     }
5092     if (has_constant_variables_gcd(p,q,d))
5093       return ;
5094     d.coord.clear();
5095     std::vector<int> permutation;
5096     polynome p_orig(p),q_orig(q);
5097     bool exchanged=exchange_variables(p_orig,pdeg,q_orig,qdeg,permutation);
5098     if (gcdheu(p_orig,pdeg,q_orig,qdeg,p_orig,np_simp,q_orig,nq_simp,d,d_content,false,false)){
5099       if (exchanged)
5100 	d.reorder(permutation);
5101       d *= d_content;
5102       return ;
5103     }
5104     d=gcdpsr(p_orig,q_orig);
5105     if (exchanged)
5106       d.reorder(permutation);
5107     // if integers only, should add here gcd using modgcd
5108     d *= d_content;
5109     if (!d.coord.empty() && d.coord.front().value.type==_MOD)
5110       d *= inv(d.coord.front().value,context0);
5111     return ;
5112   }
5113 
gcd(const polynome & p,const polynome & q,polynome & d)5114   void gcd(const polynome & p,const polynome & q,polynome & d){
5115 #ifdef TIMEOUT
5116     control_c();
5117 #endif
5118     if (ctrl_c || interrupted) {
5119       interrupted = true; ctrl_c=false;
5120       d=monomial<gen>(gensizeerr(gettext("Stopped by user interruption.")),p.dim);
5121       return ;
5122     }
5123     if (p.coord.empty()){
5124       d=q;
5125       return;
5126     }
5127     if (q.coord.empty()){
5128       d=p;
5129       return ;
5130     }
5131     /* if (p==q)
5132        return p; */
5133     if (p.dim==0){
5134       index_t i;
5135       d=polynome( monomial<gen>(gcd(p.constant_term(),q.constant_term(),context0),i));
5136       return ;
5137     }
5138     d.dim=p.dim;
5139     d.coord.clear();
5140     index_t pback=p.coord.back().index.iref(),qback=q.coord.back().index.iref();
5141     if (!is_zero(pback))
5142       pback=p.gcddeg();
5143     if (!is_zero(qback))
5144       qback=q.gcddeg();
5145     if (!is_zero(pback) || !is_zero(qback)){
5146       index_t dback=index_gcd(pback,qback);
5147       polynome pshift=p.shift(-pback), qshift=q.shift(-qback);
5148       gcd(pshift,qshift,d);
5149       if (!is_zero(dback))
5150 	d=d.shift(dback);
5151       return;
5152     }
5153     gcd_gcdpart(p,q,d,true);
5154   }
5155 
gcd(const polynome & p,const polynome & q)5156   polynome gcd(const polynome & p,const polynome & q){
5157     polynome d(p.dim);
5158     gcd(p,q,d);
5159     return d;
5160   }
5161 
egcdlgcd(const polynome & p1,const polynome & p2,polynome & u,polynome & v,polynome & d)5162   void egcdlgcd(const polynome &p1, const polynome & p2, polynome & u,polynome & v,polynome & d){
5163     TegcdTlgcd(p1,p2,u,v,d);
5164   }
5165 
egcd(const polynome & p1,const polynome & p2,polynome & u,polynome & v,polynome & d)5166   void egcd(const polynome &p1, const polynome & p2, polynome & u,polynome & v,polynome & d){
5167     if (try_hensel_egcd(p1,p2,u,v,d))
5168       return;
5169     polynome g=gcd(p1,p2);
5170     if (g.lexsorted_degree()){
5171       egcd(p1/g,p2/g,u,v,d);
5172       d=g*d;
5173       return;
5174     }
5175     if (p1.dim!=1){
5176       egcdpsr(p1,p2,u,v,d);
5177       return;
5178     }
5179     gen p1g,p2g;
5180     int p1t=coefftype(p1,p1g);
5181     int p2t=coefftype(p2,p2g);
5182     if (p1t==0 && p2t==0
5183 	&& p1.lexsorted_degree()>=GIAC_PADIC/2 && p2.lexsorted_degree()>=GIAC_PADIC/2
5184 	){
5185       if (debug_infolevel>2)
5186 	CERR << CLOCK()*1e-6 << "starting extended gcd degrees " << p1.lexsorted_degree() << " " << p2.lexsorted_degree() << '\n';
5187       vecteur G,p1v,p2v;
5188       polynome2poly1(g,1,G);
5189       polynome2poly1(p1,1,p1v);
5190       polynome2poly1(p2,1,p2v);
5191       // solve sylvester matrix * []=d
5192       matrice S=sylvester(p1v,p2v);
5193       S=mtran(S);
5194       int add=int(p1v.size()+p2v.size()-G.size()-2);
5195       vecteur V=mergevecteur(vecteur(add,0),G);
5196       vecteur U=linsolve(S,V,context0);
5197       gen D;
5198       lcmdeno(U,D,context0);
5199       if (is_positive(-D,context0)){
5200 	D=-D;
5201 	for (iterateur it=U.begin(),itend=U.end();it!=itend;++it)
5202 	  *it=-*it;
5203       }
5204       G=multvecteur(D,G);
5205       V=vecteur(U.begin()+p2v.size()-1,U.end());
5206       U=vecteur(U.begin(),U.begin()+p2v.size()-1);
5207       poly12polynome(U,1,u);
5208       poly12polynome(V,1,v);
5209       poly12polynome(G,1,d);
5210       if (0){ // debug code
5211 	polynome u1,v1,d1;
5212 	egcdlgcd(p1,p2,u1,v1,d1);
5213 	if (is_positive(-d1.coord.front().value,context0)){
5214 	  d1=-d1; u1=-u1; v1=-v1;
5215 	}
5216 	if (u!=u1 || v!=v1 || d!=d1)
5217 	  CERR << "err" << '\n';
5218       }
5219       return;
5220     }
5221     if (p1t==_EXT && p2t==_EXT && p1g.type==_EXT && p2g.type==_EXT && *(p1g._EXTptr+1)==*(p2g._EXTptr+1) && (p1g._EXTptr+1)->type==_VECT){
5222       vecteur G;
5223       polynome2poly1(g,1,G);
5224       polynome pmini(2),P1,P2;
5225       algext_vmin2pmin(*(p1g._EXTptr+1)->_VECTptr,pmini);
5226       polynome P1n(1),P2n(1);
5227       if (algext_convert(p1,p1g,P1) && algext_convert(p2,p1g,P2)){
5228 	if (algnorme(P1,pmini,P1n) && algnorme(P2,pmini,P2n)){
5229 	  // first solve norme(p1)*un+norme(p2)*vn=d
5230 	  // then norme(p1)/p1*un*p1+norme(p2)/p2*vn*p2=d
5231 	  // hence u=norme(p1)/p1*un and v=norme(p2)/p2*vn
5232 	  int p1t=coefftype(P1n,p1g);
5233 	  int p2t=coefftype(P2n,p2g);
5234 	  polynome P12g=gcd(P1n,P2n);
5235 	  if (p1t==0 && p2t==0 && P12g.lexsorted_degree()==0){
5236 	    //CERR << P1n % pp1 << '\n';
5237 	    //CERR << P2n % pp2 << '\n';
5238 	    P1=P1n/p1;
5239 	    P2=P2n/p2;
5240 	    // solve sylvester matrix * []=d
5241 	    matrice S=sylvester(polynome2poly1(P1n,1),polynome2poly1(P2n,1));
5242 	    S=mtran(S);
5243 	    vecteur V(S.size());
5244 	    V[S.size()-1]=G[0];
5245 	    vecteur U(linsolve(S,V,context0));
5246 	    gen D;
5247 	    lcmdeno(U,D,context0);
5248 	    G=multvecteur(D,G);
5249 	    poly12polynome(G,1,d);
5250 	    int p2s=P2n.lexsorted_degree();
5251 	    V=vecteur(U.begin()+p2s,U.end());
5252 	    poly12polynome(V,1,v);
5253 	    v=(v*P2) % p1;
5254 	    U=vecteur(U.begin(),U.begin()+p2s);
5255 	    poly12polynome(U,1,u);
5256 	    u=(u*P1) % p2;
5257 	    //CERR << (operator_times(u,p1,0)+operator_times(v,p2,0))/D << '\n';
5258 	    return;
5259 	  }
5260 	}
5261       }
5262     }
5263     if (p1t==_EXT && p2t==0 && p1g.type==_EXT && (p1g._EXTptr+1)->type==_VECT){
5264       vecteur G,p2v;
5265       polynome2poly1(g,1,G);
5266       polynome2poly1(p2,1,p2v);
5267       polynome pmini(2),P1;
5268       algext_vmin2pmin(*(p1g._EXTptr+1)->_VECTptr,pmini);
5269       polynome P1n(1);
5270       if (algext_convert(p1,p1g,P1)){
5271 	if (algnorme(P1,pmini,P1n)){
5272 	  // first solve norme(p1)*un+p2*v=d
5273 	  // then norme(p1)/p1*un*p1+v*p2=d
5274 	  // hence u=norme(p1)/p1*un
5275 	  int p1t=coefftype(P1n,p1g);
5276 	  if (p1t==0){
5277 	    P1=P1n/p1;
5278 	    // solve sylvester matrix * []=d
5279 	    matrice S=sylvester(polynome2poly1(P1n,1),p2v);
5280 	    S=mtran(S);
5281 	    vecteur V(vecteur(S.size()));
5282 	    V[S.size()-1]=G[0];
5283 	    vecteur U(linsolve(S,V,context0));
5284 	    gen D;
5285 	    lcmdeno(U,D,context0);
5286 	    G=multvecteur(D,G);
5287 	    poly12polynome(G,1,d);
5288 	    int p2s=int(p2v.size())-1;
5289 	    V=vecteur(U.begin()+p2s,U.end());
5290 	    poly12polynome(V,1,v);
5291 	    U=vecteur(U.begin(),U.begin()+p2s);
5292 	    poly12polynome(U,1,u);
5293 	    u=u*P1;
5294 	    //CERR << (operator_times(u,p1,0)+operator_times(v,p2,0))/D << '\n';
5295 	    return;
5296 	  }
5297 	}
5298       }
5299     }
5300     if (p2t==_EXT && p1t==0 && p2g.type==_EXT && (p2g._EXTptr+1)->type==_VECT){
5301       egcd(p2,p1,v,u,d);
5302       return;
5303     }
5304     egcdlgcd(p1,p2,u,v,d);
5305     if (is_positive(-d.coord.front().value,context0)){
5306       d=-d; u=-u; v=-v;
5307     }
5308     if (d.coord.front().value.type==_USER){
5309       gen dinv=inv(d.coord.front().value,context0);
5310       if (dinv.type==_USER){
5311 	d=dinv*d;
5312 	u=dinv*u;
5313 	v=dinv*v;
5314       }
5315     }
5316   }
5317 
5318   /* Factorization */
5319 
5320   // build a multivariate poly
5321   // with normal coeff from a multivariate poly with multivariate poly coeffs
unsplitmultivarpoly(const polynome & p,int inner_dim)5322   polynome unsplitmultivarpoly(const polynome & p,int inner_dim){
5323     polynome res(p.dim+inner_dim);
5324     index_t inner_index,outer_index;
5325     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
5326     for (;it!=itend;++it){
5327       outer_index=it->index.iref();
5328       if (it->value.type!=_POLY){
5329 	for (int j=0;j<inner_dim;++j)
5330 	  outer_index.push_back(0);
5331 	res.coord.push_back(monomial<gen>(it->value,outer_index));
5332       }
5333       else {
5334 	vector< monomial<gen> >::const_iterator jt=it->value._POLYptr->coord.begin(),jtend=it->value._POLYptr->coord.end();
5335 	for (;jt!=jtend;++jt){
5336 	  inner_index= jt->index.iref();
5337 	  res.coord.push_back(monomial<gen>(jt->value,mergeindex(outer_index,inner_index)));
5338 	}
5339       }
5340     }
5341     return res;
5342   }
5343 
5344   // build from a multivariate poly with normal coeff
5345   // a multivariate poly with multivariate poly coeffs
splitmultivarpoly(const polynome & p,int inner_dim)5346   polynome splitmultivarpoly(const polynome & p,int inner_dim){
5347     int outer_dim=p.dim-inner_dim;
5348     index_t cur_outer(outer_dim);
5349     polynome cur_inner(inner_dim);
5350     polynome res(outer_dim);
5351     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
5352     for (; it!=itend;++it){
5353       index_t outer_index(it->index.begin(),it->index.begin()+outer_dim);
5354       index_t inner_index(it->index.begin()+outer_dim,it->index.end());
5355       if (outer_index!=cur_outer){
5356 	if (!is_zero(cur_inner))
5357 	  res.coord.push_back(monomial<gen>(cur_inner,cur_outer));
5358 	cur_inner.coord.clear();
5359 	cur_outer=outer_index;
5360       }
5361       cur_inner.coord.push_back(monomial<gen>(it->value,inner_index));
5362     }
5363     if (!is_zero(cur_inner))
5364       res.coord.push_back(monomial<gen>(cur_inner,cur_outer));
5365     return res;
5366   }
5367 
5368   // if one coeff of p is a polynomial, we must build a multivariate poly
5369   // with normal coeff from a multivariate poly with multivariate poly coeffs
poly_factor(const polynome & p,int inner_dim,polynome & p_content,factorization & f,bool with_sqrt,bool complexmode,gen & extra_div)5370   static bool poly_factor(const polynome & p, int inner_dim,polynome & p_content,factorization & f,bool with_sqrt,bool complexmode,gen & extra_div){
5371     // convert p -> pp
5372     polynome pp(unsplitmultivarpoly(p,inner_dim)),pp_content(p.dim+inner_dim);
5373     // factorize pp
5374     // setting with_sqrt to false otherwise problems with mixed num/exact
5375     // e.g. EIGENVAL([[4,x],[r,p]])
5376     if (!factor(pp,pp_content,f,false,false,complexmode,1,extra_div))
5377       return false;
5378     // convert back pp_content -> p_content and each term of f
5379     p_content=splitmultivarpoly(pp_content,inner_dim);
5380     factorization::iterator f_it=f.begin(),f_itend=f.end();
5381     for (;f_it!=f_itend;++f_it)
5382       f_it->fact=splitmultivarpoly(f_it->fact,inner_dim);
5383     return true;
5384   }
5385 
5386   // Yun algorithm in finite field of characteristic n
5387   // Must be called recursively since it will not detect powers multiple of n
partialsquarefree_fp(const polynome & p,unsigned n,polynome & c,factorization & v)5388   static void partialsquarefree_fp(const polynome & p,unsigned n,polynome & c,factorization & v){
5389     v.clear();
5390     polynome y(p.derivative()),w(p);
5391     y=smod(y,gen(int(n)));
5392     c=simplify(w,y);
5393     // If p=p_1*p_2^2*...*p_n^n,
5394     // then c=gcd(p,p')=Pi_{i s.t. i%n!=0} p_i^{i-1} Pi_{i s.t. i%n==0} p_i^i
5395     // w=p/c=Pi_{i%n>=1} p_i,
5396     // y=p'/c=Sum_{i%n>=1} ip_i'*pi_{j!=i, j%n>=1} p_j
5397     y=y-w.derivative();
5398     y=smod(y,gen(int(n)));
5399     // y=Sum_{i%n>=2} (i-1)p_i'*pi_{j!=i,j%n!=0} p_j
5400     int k=1;
5401     while(!y.coord.empty()){
5402       // y=sum_{i%n >= k+1} (i-k) p_i' * pi_{j!=i, j>=k} p_j
5403       polynome g=simplify(w,y);
5404       if (!Tis_one(g))
5405 	v.push_back(facteur< polynome >(g,k));
5406       // extract one time the factors of multiplicity k mod n
5407       c=c/w;
5408       // this push p_k, now w=pi_{i%n>=k+1} p_i and
5409       // y=sum_{i%n>=k+1} (i-k) p_i' * pi_{j!=i, j%n>=k+1} p_j
5410       y=y-w.derivative();
5411       y=smod(y,gen(int(n)));
5412       // y=sum_{i%n>=k+1} (i-(k+1)) p_i' * pi_{j!=i, j%n>=k+1} p_j
5413       k++;
5414     }
5415     if (!Tis_one(w))
5416       v.push_back(facteur< polynome >(w,k));
5417     // at the end c contains Pi_{i} p_i^{i-(i%n)}
5418   }
5419 
5420   // Yun algorithm in finite field of characteristic n
5421   // Requires factorization_compress after
uncompressed_squarefree_fp(const polynome & p,unsigned n,unsigned exposant)5422   static factorization uncompressed_squarefree_fp(const polynome & p,unsigned n,unsigned exposant){
5423     factorization res;
5424     if (Tis_one(p))
5425       return res;
5426     polynome c(p.dim);
5427     partialsquarefree_fp(p,n,c,res);
5428     if (Tis_one(c))
5429       return res;
5430     if (Tis_constant(c)){
5431       // res.push_back(facteur<polynome>(c,1));
5432       return res;
5433     }
5434     // Check that all first degrees are divisible by n
5435     // and search for a variable such that one degree is not divisible by n
5436     vector< monomial<gen> >::const_iterator It=c.coord.begin(),Itend=c.coord.end();
5437     for (;It!=Itend;++It){
5438       const index_t &i=It->index.iref();
5439       for (int j=0;j<c.dim;++j){
5440 	if (i[j]%n){
5441 #ifndef NO_STDEXCEPT
5442 	  if (j==0)
5443 	    setsizeerr(gettext("Square free factor mod bug")+c.print());
5444 #endif
5445 	  // call complete factorization after reordering
5446 	  c.reorder(transposition(0,j,c.dim));
5447 	  factorization cf(squarefree_fp(c,n,exposant));
5448 	  factorization::iterator jt=cf.begin(),jtend=cf.end();
5449 	  for (;jt!=jtend;++jt){
5450 	    jt->fact.reorder(transposition(0,j,c.dim));
5451 	    res.push_back(*jt);
5452 	  }
5453 	  return res;
5454 	}
5455       }
5456     }
5457     polynome b(c.dividealldegrees(n));
5458     if (exposant!=1){
5459       // replace all coeffs of b by coeff^(p^(n-1))
5460       // since in F_{p^n} we have a=(a^(p^(n-1)))^p which is not a^p
5461       std::vector< monomial<gen> > ::iterator it=b.coord.begin(),itend=b.coord.end();
5462       int ntoexposant=pow(n,exposant-1).val;
5463       for (;it!=itend;++it){
5464 	it->value=pow(it->value,ntoexposant);
5465       }
5466     }
5467     // Note that this is not correct, we must compute gcd of res and resn
5468     // that have the same residue modulo n
5469     // Example factor( (x+1)^3*(x-1)^4 %3 )
5470     // puts x-1 in res and (x^2-1)^3 in c
5471     // Hence we must call factorization_compress at the end
5472     factorization resn(uncompressed_squarefree_fp(b,n,exposant));
5473     factorization::const_iterator it=resn.begin(),itend=resn.end();
5474     for (;it!=itend;++it){
5475       res.push_back(facteur<polynome>(it->fact,it->mult*n));
5476     }
5477     return res;
5478   }
5479 
5480   // Compress factorization, required for sqff on finite field
factorization_compress(factorization & sqff_f)5481   static void factorization_compress(factorization & sqff_f){
5482     factorization sqfftmp(sqff_f);
5483     sqff_f.clear();
5484     vecteur vtmp;
5485     int pos;
5486     factorization::const_iterator it=sqfftmp.begin(),itend=sqfftmp.end();
5487     for (;it!=itend;++it){
5488       if ( (pos=equalposcomp(vtmp,it->fact)) ){
5489 	sqff_f[pos-1].mult += it->mult;
5490       }
5491       else {
5492 	vtmp.push_back(it->fact);
5493 	sqff_f.push_back(*it);
5494       }
5495     }
5496   }
5497 
sqff_ffield_factor(const factorization & sqff_f,int n,environment * env,factorization & f)5498   bool sqff_ffield_factor(const factorization & sqff_f,int n,environment * env,factorization & f){
5499     // Now factorize each factor
5500     factorization::const_iterator it=sqff_f.begin(),itend=sqff_f.end();
5501     for (;it!=itend;++it){
5502       // const facteur<polynome> & fp=*it;
5503       const polynome & itfact = it->fact;
5504       if (itfact.lexsorted_degree()<=1){
5505 	f.push_back(*it);
5506 	continue;
5507       }
5508       if (itfact.dim>1){
5509 	vecteur b(itfact.dim-1);
5510 	polynome Fb,Gb;
5511 	if (find_good_eval(itfact,itfact,Fb,Gb,b,(debug_infolevel>=2))){
5512 	  if (is_zero(b)){
5513 	    factorization sqff_F0(squarefree_fp(Fb,n,1)),v0;
5514 	    if (!sqff_ffield_factor(sqff_F0,n,env,v0))
5515 	      return false;
5516 	    if (try_hensel_lift_factor(itfact,Fb,v0,it->mult,f))
5517 	      continue;
5518 	  }
5519 	  int essaimax=10;
5520 	  for (int essai=0;essai<essaimax;++essai){
5521 	    // try to translate
5522 	    int b0d=itfact.dim;
5523 	    vecteur vb0(b0d),vb1(b0d),lv(b0d);
5524 	    lv[0]=gen("x0",context0);
5525 	    // int hasard=rand()/(RAND_MAX/env->modulo.val);
5526 	    int hasard=0;
5527 	    vb0[0]=sym2r(lv[0]+hasard,lv,context0);
5528 	    vb1[0]=sym2r(lv[0]-hasard,lv,context0);
5529 	    for (int i=1;i<b0d;i++){
5530 	      int hasard1=0; // rand()/(RAND_MAX/env->modulo.val);
5531 	      int hasard2=std_rand()/(RAND_MAX/env->modulo.val);
5532 	      lv[i]=gen("x"+print_INT_(i),context0);
5533 	      vb0[i]=sym2r(lv[i]+hasard1*lv[0]+hasard2,lv,context0);
5534 	      vb1[i]=sym2r(lv[i]-hasard1*lv[0]-hasard2,lv,context0);
5535 	    }
5536 	    gen pb=peval(unmodularize(itfact),vb0,env->modulo,false),num,den;
5537 	    fxnd(pb,num,den);
5538 	    if (num.type!=_POLY){
5539 #ifndef NO_STDEXCEPT
5540 	      setsizeerr();
5541 #endif
5542 	      return false;
5543 	    }
5544 	    polynome ptrans=*num._POLYptr;
5545 	    modularize(ptrans,env->modulo);
5546 	    factorization ftrans,v0;
5547 	    b=vecteur(ptrans.dim-1);
5548 	    find_good_eval(ptrans,ptrans,Fb,Gb,b,(debug_infolevel>=2));
5549 	    if (is_zero(b)){
5550 	      gen extra_div=1;
5551 	      factor(Fb,Gb,v0,false,false,false,1,extra_div);
5552 	      if (is_one(v0.front().fact))
5553 		v0.erase(v0.begin());
5554 	      if (try_hensel_lift_factor(ptrans,Fb,v0,it->mult,ftrans)){
5555 		factorization::const_iterator it=ftrans.begin(),itend=ftrans.end();
5556 		for (;it!=itend;++it){
5557 		  pb=peval(unmodularize(it->fact),vb1,env->modulo,false);
5558 		  fxnd(pb,num,den);
5559 		  if (num.type!=_POLY){
5560 #ifndef NO_STDEXCEPT
5561 		    setsizeerr();
5562 #endif
5563 		    return false;
5564 		  }
5565 		  polynome tmp(*num._POLYptr);
5566 		  modularize(tmp,env->modulo);
5567 		  f.push_back(facteur<polynome>(tmp,it->mult));
5568 		}
5569 		essaimax=0;
5570 	      }
5571 	    }
5572 	  } // end for essai<essaimax
5573 	  if (essaimax==0)
5574 	    continue;
5575 	}
5576 #ifndef NO_STDEXCEPT
5577 	setsizeerr(gettext("Multivariate finite field factorzation expects a unitary polynomial regular at 0. Try to translate with respect to one variable"));
5578 #endif
5579 	return false;
5580       }
5581       // convert to vector
5582       modpoly Qtry(modularize(
5583 			      unmodularize(itfact)
5584 			      //env->moduloon?unmodularize(itfact):it->fact
5585 			      ,n,env));
5586       if (is_undef(Qtry)){
5587 #ifndef NO_STDEXCEPT
5588 	setsizeerr();
5589 #endif
5590 	return false;
5591       }
5592       // and call sqff mod factor
5593       vector< facteur<modpoly> > wf;
5594       vector<modpoly> qmat;
5595       // qmatrix(Qtry,env,qmat,0);
5596       if (!ddf(Qtry,qmat,env,wf)){
5597 #ifndef NO_STDEXCEPT
5598 	setsizeerr();
5599 #endif
5600 	return false;
5601       }
5602       vector<modpoly> w;
5603       if (!cantor_zassenhaus(wf,qmat,env,w)){
5604 #ifndef NO_STDEXCEPT
5605 	setsizeerr();
5606 #endif
5607 	return false;
5608       }
5609       // put result in f
5610       vector<modpoly>::const_iterator jt=w.begin(),jtend=w.end();
5611       gen gtmp;
5612       for ( ;jt!=jtend;++jt){
5613 	polynome tmp(unmodularize(*jt));
5614 	gtmp=env->moduloon?makemod(tmp,n):tmp;
5615 	if (gtmp.type==_POLY)
5616 	  f.push_back(facteur<polynome>(*gtmp._POLYptr,it->mult));
5617       }
5618     }
5619     // cleanup, set first coeff to 1
5620     factorization::iterator jt=f.begin(),jtend=f.end();
5621     for (;jt!=jtend;++jt){
5622       gen coeff=jt->fact.coord.front().value;
5623       if (coeff.type==_MOD)
5624 	coeff = inv(coeff,context0);
5625       jt->fact = coeff * jt->fact;
5626     }
5627     return true;
5628   }
5629 
squarefree_fp(const polynome & p,unsigned n,unsigned exposant)5630   factorization squarefree_fp(const polynome & p,unsigned n,unsigned exposant){
5631     factorization res(uncompressed_squarefree_fp(p,n,exposant));
5632     factorization_compress(res);
5633     return res;
5634   }
5635 
5636   // p is primitive wrt the main var
mod_factor(const polynome & p_orig,polynome & p_content,int n,factorization & f)5637   bool mod_factor(const polynome & p_orig,polynome & p_content,int n,factorization & f){
5638     if (!is_probab_prime_p(n))
5639       return false;
5640     environment env;
5641     env.moduloon = true;
5642     env.modulo=n;
5643     env.pn=n;
5644     // Check that all coeff are mod
5645     polynome p(p_orig);
5646     vector< monomial<gen> >::iterator pit=p.coord.begin(),pitend=p.coord.end();
5647     for (;pit!=pitend;++pit){
5648       if (pit->value.type!=_MOD)
5649 	pit->value=makemod(pit->value,n);
5650       gen & tmp = *(pit->value._MODptr+1);
5651       if (tmp.type!=_INT_ || tmp.val!=n){
5652 #ifndef NO_STDEXCEPT
5653 	setsizeerr();
5654 #endif
5655 	return false;
5656       }
5657       gen & val = *(pit->value._MODptr);
5658       if (val.type==_CPLX)
5659 	env.complexe=true;
5660     }
5661 #ifdef HAVE_LIBNTL
5662 #ifdef HAVE_LIBPTHREAD
5663     int locked=pthread_mutex_trylock(&ntl_mutex);
5664 #endif // HAVE_LIBPTHREAD
5665     if (p.dim==1 && !locked){
5666       bool res=true;
5667 #ifndef NO_STDEXCEPT
5668       try {
5669 #endif
5670 	vecteur v;
5671 	if (p.dim!=1){
5672 #ifndef NO_STDEXCEPT
5673 	  setsizeerr(gettext("gausspol.cc/mod_factor"));
5674 #endif
5675 	  return false;
5676 	}
5677 	if (p.coord.empty()){
5678 #ifndef NO_STDEXCEPT
5679 	  setsizeerr();
5680 #endif
5681 	  return false;
5682 	}
5683 	int deg=p.lexsorted_degree();
5684 	int curpow=deg;
5685 	v.reserve(deg+1);
5686 	vector< monomial<gen> >::const_iterator ppit=p.coord.begin();
5687 	vector< monomial<gen> >::const_iterator ppitend=p.coord.end();
5688 	for (;ppit!=ppitend;++ppit){
5689 	  int newpow=ppit->index.front();
5690 	  for (;curpow>newpow;--curpow)
5691 	    v.push_back(0);
5692 	  if (ppit->value.type==_INT_)
5693 	    v.push_back(ppit->value);
5694 	  if (ppit->value.type==_MOD)
5695 	    v.push_back(*ppit->value._MODptr);
5696 	  --curpow;
5697 	}
5698 	for (;curpow>-1;--curpow)
5699 	  v.push_back(0);
5700 	// FIXME NTL works on monic polynomials only!!
5701 	gen v0=v.front();
5702 	if (!is_one(v0)){
5703 	  p_content = p_content*v0;
5704 	  v0=invmod(v0,gen(n));
5705 	  v = operator_times(v,v0,&env);
5706 	}
5707 	if (n==2){
5708 	  NTL::GF2X ntlf(modpoly2GF2X(v));
5709 	  NTL::vec_pair_GF2X_long fres(NTL::CanZass(ntlf,0));
5710 	  int s=fres.length();
5711 	  for (int i=0;i<s;i++){
5712 	    modpoly res( GF2X2modpoly(fres[i].a));
5713 	    f.push_back(facteur<polynome>(*makemod(unmodularize(res),2)._POLYptr,fres[i].b));
5714 	  }
5715 	}
5716 	else {
5717 	  NTL::ZZ_p::init(inttype2ZZ(n));
5718 	  NTL::ZZ_pX ntlf(modpoly2ZZ_pX(v));
5719 	  NTL::vec_pair_ZZ_pX_long fres(NTL::CanZass(ntlf,0));
5720 	  int s=fres.length();
5721 	  for (int i=0;i<s;i++){
5722 	    modpoly res( ZZ_pX2modpoly(fres[i].a));
5723 	    f.push_back(facteur<polynome>(*makemod(unmodularize(res),n)._POLYptr,fres[i].b));
5724 	  }
5725 	}
5726 #ifndef NO_STDEXCEPT
5727       } catch (std::runtime_error & e){
5728 	res=false;
5729       }
5730 #endif
5731 #ifdef HAVE_LIBPTHREAD
5732       pthread_mutex_unlock(&ntl_mutex);
5733 #endif
5734       return res;
5735     } // end !locked
5736 #endif
5737     // sqff
5738     factorization sqff_f(squarefree_fp(p,n,1));
5739     if (!sqff_ffield_factor(sqff_f,n,&env,f))
5740       return false;
5741     factorization_compress(f);
5742     // cleanup cst coeff
5743     gen coeff(1);
5744     factorization::iterator it=f.begin(),itend=f.end();
5745     for (;it!=itend;++it){
5746       coeff=coeff*pow(it->fact.coord.front().value,it->mult,context0);
5747     }
5748     coeff=p.coord.front().value/coeff;
5749     p_content=coeff*p_content;
5750     return true;
5751   }
5752 
5753   // factorization over an algebraic extension
5754   // the main variable of G is the algebraic extension variable
5755   // the minimal polynomial of this variable is p_mini
5756   // G is assumed to be square-free
5757   // See algorithm 3.6.4 in Henri Cohen book starting at step 3
5758   // Gtry is non 0 if algfactor has detected a possible factor
algfactor(const polynome & G,const polynome & p_mini,int & k,factorization & f,bool complexmode,gen & extra_div,polynome & Gtry)5759   bool algfactor(const polynome & G,const polynome & p_mini,int & k,factorization & f,bool complexmode,gen & extra_div,polynome & Gtry){
5760     // search sqff norm
5761     polynome norme(G.dim),temp(G.dim),p_mini1(p_mini);
5762     p_mini1.reorder(transposition(0,1,G.dim));
5763     p_mini1=p_mini1.trunc1();
5764     k=-1;
5765     for (;;) {
5766       ++k;
5767       // replace X by X-k*Y in G and _compute resultant
5768       if (k){
5769 	vecteur v;
5770 	polynome2poly1(G,2,v); // X is the second var
5771 	polynome decal(G.dim-1);
5772 	decal.coord.push_back(monomial<gen>(gen(-k),1,G.dim-1)); // -k*main_var
5773 	v=taylor(v,decal);
5774 	poly12polynome(v,2,temp,G.dim);
5775 	// take remainder otherwise algnorme is too slow
5776 	temp = temp % p_mini;
5777 	if (!algnorme(temp,p_mini,norme))
5778 	  norme=resultant(temp,p_mini).trunc1();
5779       }
5780       else {
5781 #if 0 // IMPROVE: find a good criterion to enable!
5782 	if (debug_infolevel)
5783 	  CERR << CLOCK()*1e-6 << " sylvester resultant begin" << '\n';
5784 	vecteur Gv(polynome2poly1(G,1)),p_miniv(polynome2poly1(p_mini,1));
5785 	matrice S=sylvester(p_miniv,Gv);
5786 	S=mtran(S);
5787 	gen g=det_minor(S,vecteur(0),false,context0);
5788 	if (debug_infolevel)
5789 	  CERR << CLOCK()*1e-6 << " sylvester resultant end" << '\n';
5790 	if (g.type==_POLY)
5791 	  norme=*g._POLYptr;
5792 	else
5793 #endif
5794 	  norme=resultant(G,p_mini).trunc1();
5795       }
5796       if (gcd(norme,p_mini1).lexsorted_degree())
5797 	continue;
5798       // check that norme is squarefree, first find inner dimension
5799       polynome dnorme=norme.derivative();
5800       int innerdim=0;
5801       vector< monomial<gen> >::const_iterator ckalg_it=norme.coord.begin(),ckalg_itend=norme.coord.end();
5802       for (; ckalg_it!=ckalg_itend;++ckalg_it){
5803 	if (ckalg_it->value.type==_POLY){
5804 	  innerdim=ckalg_it->value._POLYptr->dim;
5805 	  break;
5806 	}
5807       }
5808       // convert to usual multivariate polynomials
5809       polynome N(unsplitmultivarpoly(norme,innerdim)),Np(unsplitmultivarpoly(norme.derivative(),innerdim));
5810       polynome GG=gcd(N,Np);
5811       if (!GG.lexsorted_degree()){
5812 	break;
5813       }
5814       else {
5815 	if (k==0 && innerdim==0 && !Gtry.coord.empty()){
5816 	  factorization ftry=sqff(GG);
5817 	  int extdeg=p_mini.lexsorted_degree();
5818 	  GG=polynome(monomial<gen>(plus_one,0,Gtry.dim));
5819 	  for (int i=0;i<ftry.size();++i){
5820 	    GG=GG*pow(ftry[i].fact,ftry[i].mult / (extdeg-1));
5821 	  }
5822 	  Np=Gtry % GG;
5823 	  if (Np.coord.empty()){
5824 	    Gtry.coord.swap(GG.coord);
5825 	    return true;
5826 	  }
5827 	}
5828       }
5829     }
5830     if (debug_infolevel)
5831       CERR << CLOCK()*1e-6 << " norme factor begin" << '\n';
5832     bool test=factor(norme,temp,f,true,false,complexmode,1,extra_div);
5833     if (debug_infolevel)
5834       CERR << CLOCK()*1e-6 << " norme factor end" << '\n';
5835     Gtry.coord.clear();
5836     return test;
5837   }
5838 
algext_vmin2pmin(const vecteur & v_mini,polynome & p_mini)5839   void algext_vmin2pmin(const vecteur & v_mini,polynome & p_mini){
5840     const_iterateur tmp_it=v_mini.begin(),tmp_itend=v_mini.end();
5841     for (int d=int(tmp_itend-tmp_it)-1;tmp_it!=tmp_itend;++tmp_it,--d){
5842       if (is_zero(*tmp_it))
5843 	continue;
5844       p_mini.coord.push_back(monomial<gen>(*tmp_it,d,1,p_mini.dim));
5845     }
5846   }
5847 
5848   // add a dimension in front of pcur for algebraic extension variable
algext_convert(const polynome & pcur,const gen & e,polynome & p_y)5849   bool algext_convert(const polynome & pcur,const gen & e,polynome & p_y){
5850     p_y.dim=pcur.dim+1;
5851     vector< monomial<gen> >::const_iterator p_it=pcur.coord.begin(),p_itend=pcur.coord.end();
5852     for (;p_it!=p_itend;++p_it){
5853       if (p_it->value.type!=_EXT){
5854 	p_y.coord.push_back(p_it->untrunc1());
5855 	continue;
5856       }
5857       if (*(p_it->value._EXTptr+1)!=*(e._EXTptr+1)){
5858 #ifndef NO_STDEXCEPT
5859 	setsizeerr(gettext("Factor: Only one algebraic extension allowed"));
5860 #endif
5861 	return false;
5862       }
5863       // convert the polynomial of the algebraic extension generator
5864       index_t ii=p_it->index.iref();
5865       ii.insert(ii.begin(),0);
5866       p_y=p_y+poly1_2_polynome(*(p_it->value._EXTptr->_VECTptr),p_y.dim).shift(ii);
5867     }
5868     // p_y=p_y/Tcontent(p_y);
5869     return true;
5870   }
5871 
5872   static bool do_factor(const polynome &p,polynome & p_content,factorization & f,bool isprimitive,bool with_sqrt,bool complexmode,const gen & divide_an_by,gen & extra_div);
5873 
has_embedded_poly(const polynome & p)5874   bool has_embedded_poly(const polynome & p){
5875     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
5876     for (;it!=itend;++it){
5877       if (it->value.type==_POLY)
5878 	return true;
5879     }
5880     return false;
5881   }
5882 
ext_factor(const polynome & p,const gen & e,gen & an,polynome & p_content,factorization & f,bool complexmode,gen & extra_div)5883   bool ext_factor(const polynome &p,const gen & e,gen & an,polynome & p_content,factorization & f,bool complexmode,gen & extra_div){
5884     if (e._EXTptr->type!=_VECT){
5885 #ifndef NO_STDEXCEPT
5886       settypeerr(gettext("Modular factorization not yet accessible"));
5887 #endif
5888       return false;
5889     }
5890     gen ip=im(p,context0);
5891     bool ip0=is_zero(ip);
5892     if (!ip0 || complexmode){
5893       gen anreal(an),extra_divreal(extra_div); factorization freal; polynome p_contentreal(p_content);
5894       if (ip0 && !ext_factor(p,e,anreal,p_contentreal,freal,false,extra_divreal))
5895 	return false;
5896       // replace i by [1,0]:[1,0,1]
5897       gen bn=1,the_ext=algebraic_EXTension(makevecteur(1,0),makevecteur(1,0,1));
5898       gen newp=re(p,context0)+the_ext*ip;
5899       if (newp.type!=_POLY)
5900 	return false;
5901       vector< monomial<gen> >::iterator it=newp._POLYptr->coord.begin(),itend=newp._POLYptr->coord.end();
5902       for (;it!=itend;++it){
5903 	if (it->value.type==_EXT)
5904 	  it->value=ext_reduce(it->value);
5905 	if (it->value.type==_FRAC && it->value._FRACptr->num.type==_EXT)
5906 	  it->value=ext_reduce(it->value._FRACptr->num)/it->value._FRACptr->den;
5907       }
5908       lcmdeno(*newp._POLYptr,bn);
5909       newp=bn*newp;
5910       for (it=newp._POLYptr->coord.begin(),itend=newp._POLYptr->coord.end();it!=itend;++it){
5911 	if (it->value.type==_EXT){
5912 	  if (the_ext.type==_EXT){
5913 	    common_EXT(*(it->value._EXTptr+1),*(the_ext._EXTptr+1),0,context0);
5914 	    the_ext=ext_reduce(the_ext);
5915 	    if (the_ext.type==_FRAC)
5916 	      the_ext=the_ext._FRACptr->num;
5917 	  }
5918 	  else
5919 	    the_ext=it->value;
5920 	}
5921       }
5922       if (e.type==_EXT){
5923 	gen ee=*(e._EXTptr+1);
5924 	common_EXT(ee,*(the_ext._EXTptr+1),0,context0);
5925 	the_ext=ext_reduce(the_ext);
5926 	if (the_ext.type==_FRAC)
5927 	  the_ext=the_ext._FRACptr->num;
5928       }
5929       for (it=newp._POLYptr->coord.begin();it!=itend;++it){
5930 	if (it->value.type==_EXT)
5931 	  it->value=ext_reduce(it->value);
5932       }
5933       gen bn2=1;
5934       lcmdeno(*newp._POLYptr,bn2);
5935       newp=bn2*newp;
5936       if (the_ext.type!=_EXT)
5937 	return false;
5938       bool res=ext_factor(*newp._POLYptr,the_ext,an,p_content,f,false,extra_div);
5939       if (f.size()==freal.size()){
5940 	an=anreal;
5941 	p_content=p_contentreal;
5942 	f=freal;
5943 	extra_div=extra_divreal;
5944 	return true;
5945       }
5946       an=an/(bn*bn2);
5947       return res;
5948     }
5949     an=p.coord.front().value;
5950     factorization fsqff=sqff(p);
5951     // factorization of each factor of fsqff
5952     factorization fz;
5953     factorization::const_iterator it=fsqff.begin(),itend=fsqff.end();
5954     for (;it!=itend;++it){
5955       polynome pcur=it->fact;
5956       gen tmp1(1); lcmdeno(pcur,tmp1);
5957       pcur=tmp1*pcur;
5958       // normalize leading term
5959       if (pcur.coord.front().value.type==_EXT){
5960 	gen pcur0=inv_EXT(pcur.coord.front().value),num,den;
5961 	fxnd(pcur0,num,den);
5962 	pcur=num*pcur;
5963       }
5964       int mult=it->mult;
5965       int d=pcur.lexsorted_degree();
5966       if (!d)
5967 	continue;
5968       if (d==1){
5969 	an=rdiv(an,pow(pcur.coord.front().value,gen(mult),context0),context0);
5970 	f.push_back(facteur<polynome>(pcur,mult));
5971 	continue;
5972       }
5973       // make a polynomial with 1 more variable: the extension
5974       vecteur v_mini;
5975       if ((e._EXTptr+1)->type==_VECT)
5976 	v_mini=*((e._EXTptr+1)->_VECTptr);
5977       else {
5978 #ifndef NO_STDEXCEPT
5979 	settypeerr(gettext("To be implemented"));
5980 #endif
5981 	return false;
5982       }
5983       // const_iterateur v_it,v_itend=v_mini.end();
5984       polynome p_y(p.dim+1);
5985       // polynome p_mini(poly12polynome(v_mini));
5986       // p_mini=p_mini.untrunc(0,2);
5987       // p_mini.reorder(transposition(0,1,2));
5988       // polynome p_mini(poly12polynome(v_mini,1,p.dim+1));
5989       polynome p_mini(p.dim+1);
5990       algext_vmin2pmin(v_mini,p_mini);
5991       if (!algext_convert(pcur,e,p_y))
5992 	return false;
5993 #if defined HAVE_LIBPARI && !defined(WIN32) // otherwise factor(x^4-4,sqrt(2)) segfault on cygwin32
5994       gen coefft;
5995       if (p_y.dim==2 && p_y.degree(1)>=4 && !complexmode && coefftype(p_y,coefft)<_POLY && coefftype(p_mini,coefft)<_POLY){
5996 	int dim=p_y.dim;
5997 	vecteur lv=makevecteur(y__IDNT_e,x__IDNT_e);
5998 	gen P=r2sym(p_y,lv,context0),Pmini=r2sym(p_mini,lv,context0),res;
5999 	swapgen(lv[0],lv[1]);
6000 	// call changed in pari.cc to nffactor() without nfinit()
6001 	// y^16-2204*y^15+3708732*y^14-2224018932*y^13+7601236038322*y^12-16871353226971624*y^11+11785784895214530912*y^10+14512858706664248868684*y^9-28159800647990521512088725*y^8+22629180037206015783743082216*y^7-4503073664215964343024123764736*y^6-18033250417520024351996412301581172*y^5+36809629124123557233363574360979382082*y^4-26522074490260067527688235446457244110348*y^3+5261395505608051233271161218542638549351612*y^2+1568113413809748536593336025794328431775552560*y+284494252767223281126819740714222484913944245281
6002 	// generated by normal(rootof([[468,-1072,3680,-5865,9664,-7886,2040,1515],[1,-2,7,-10,16,-10,-2,4,1]])+sqrt(rootof([[555066,-1338975,4229538,-7124970,10786458,-9150474,798516,2168328],[1,-2,7,-10,16,-10,-2,4,1]])))
6003 	// or A:=[[1,0,0],[rootof([[1,0,0],[1,-1,1,-1,1]]),rootof([[-1,1,-1,1],[1,-1,1,-1,1]]),rootof([[1,0,0],[1,-1,1,-1,1]])],[rootof([[1,0,1,-1],[1,-1,1,-1,1]]),rootof([[1,0],[1,-1,1,-1,1]]),0]];jordan(A);
6004 	// takes forever for pari nfinit0
6005 	if (pari_nffactor(P,Pmini,lv,res,context0) && res.type==_VECT){
6006 	  vecteur v=*res._VECTptr;
6007 	  unsigned j=0;
6008 	  lv=vecteur(1,vecteur(1,lv[0]));
6009 	  for (;j<v.size();++j){
6010 	    res=v[j];
6011 	    if (res.type!=_VECT || res._VECTptr->size()!=2)
6012 	      break;
6013 	    int mult=res._VECTptr->back().val;
6014 	    res=sym2r(res._VECTptr->front(),lv,context0);
6015 	    if (res.type==_FRAC)
6016 	      res=res._FRACptr->num;
6017 	    if (res.type!=_POLY)
6018 	      continue;
6019 	    // ? unitarize res
6020 	    *res._POLYptr=*res._POLYptr/res._POLYptr->coord.front().value;
6021 	    f.push_back(facteur<polynome>(*res._POLYptr,mult));
6022 	  }
6023 	  if (j==v.size()){ //adjust an
6024 	    factorization::const_iterator f_it=f.begin(),f_itend=f.end();
6025 	    for (;f_it!=f_itend;++f_it){
6026 	      an=rdiv(an,pow(f_it->fact.coord.front().value,gen(f_it->mult),context0),context0);
6027 	    }
6028 	    continue;// return true;
6029 	  }
6030 	}
6031       }
6032 #endif
6033       int k;
6034       polynome Gtry;
6035       // polynome Gtry(pcur);
6036       // does not work if trying to factor a rational poly over an extension
6037       if (!algfactor(p_y,p_mini,k,fz,false,extra_div,Gtry))
6038 	return false;
6039       if (!Gtry.coord.empty()){
6040 	// pcur is square free, multiplicities in ftry and fz should be 1
6041 	polynome ptmp(pcur/Gtry);
6042 	gen antmp;
6043 	if (!ext_factor(ptmp,e,antmp,p_content,fz,false,extra_div))
6044 	  return false;
6045 	factorization ftry;
6046 	polynome Gcontent(pcur.dim);
6047 	if (!do_factor(Gtry,Gcontent,ftry,true,false,false,1,extra_div))
6048 	  return false;
6049 	for (int i=0;i<ftry.size();++i)
6050 	  fz.push_back(ftry[i]);
6051 	factorization::const_iterator f_it=fz.begin(),f_itend=fz.end();
6052 	for (;f_it!=f_itend;++f_it){
6053 	  pcur=f_it->fact;
6054 	  // unitarize pcur
6055 	  pcur=pcur/pcur.coord.front().value;
6056 	  f.push_back(facteur<polynome>(pcur,mult));
6057 	}
6058 	continue;
6059       }
6060       factorization::const_iterator f_it=fz.begin(),f_itend=fz.end();
6061       if (f_itend-f_it==1){ // irreducible (after sqff)
6062 	an=rdiv(an,pow(pcur.coord.front().value,gen(mult),context0),context0);
6063 	f.push_back(facteur<polynome>(pcur,mult));
6064       }
6065       else {
6066 	gen bn(1);
6067 	polynome pcopy(pcur);
6068 	bool embedded_poly=has_embedded_poly(p_mini);
6069 	for (;f_it!=f_itend;++f_it){
6070 	  if (k){ // shift f_it->fact
6071 	    //vecteur v=polynome2poly1(f_it->fact);
6072 	    vecteur v; polynome2poly1(f_it->fact,1,v);
6073 	    vecteur decalv(2,zero);
6074 	    decalv[0]=k;
6075 	    gen decal=algebraic_EXTension(decalv,v_mini);
6076 	    v=taylor(v,decal);
6077 	    // pcur=poly12polynome(v);
6078 	    poly12polynome(v,1,pcur,f_it->fact.dim);
6079 	    if (embedded_poly)
6080 	      pcur=gcd(pcur,pcopy);
6081 	    else {
6082 	      // fix it for normal(sqrt(a*pi)/(2*sqrt(a)*sqrt(pi)));
6083 	      // dcur might have denominators inside
6084 	      if (f_it+1==f_itend){
6085 		pcur=pcopy;
6086 	      }
6087 	      else {
6088 		polynome dcur=simplify(pcur,pcopy);
6089 		dcur.coord.swap(pcur.coord);
6090 		gen t;
6091 		lcmdeno(pcopy,t);
6092 	      }
6093 	    }
6094 	  }
6095 	  else {
6096 	    if (embedded_poly)
6097 	      pcur=gcd(f_it->fact,p);
6098 	    else {
6099 	      if (f_it+1==f_itend){
6100 		pcur=pcopy;
6101 	      }
6102 	      else {
6103 		polynome fcopy(f_it->fact);
6104 		polynome dcur=simplify(fcopy,pcopy);
6105 		dcur.coord.swap(pcur.coord);
6106 		gen t;
6107 		lcmdeno(pcopy,t);
6108 	      }
6109 	    }
6110 	  }
6111 	  // unitarize pcur instead of computing bn
6112 	  pcur=pcur/pcur.coord.front().value;
6113 	  // bn=bn*pow(pcur.coord.front().value,gen(mult));
6114 	  f.push_back(facteur<polynome>(pcur,mult));
6115 	}
6116 	an=rdiv(an,bn,context0);
6117       }
6118     } // end for (;it!=itend;)
6119     return true;
6120   }
6121 
6122 
addtov(const polynome & tmp,vectpoly & v,bool with_sqrt,bool complexmode)6123   static void addtov(const polynome & tmp,vectpoly & v,bool with_sqrt,bool complexmode){
6124     if (!with_sqrt || tmp.lexsorted_degree()!=2 || tmp.dim>1)
6125       v.push_back(tmp);
6126     else {
6127       vecteur w=polynome2poly1(tmp,1);
6128       gen a=w.front(),b=w[1],c=w[2];
6129       gen delta=4*a*c-b*b,deltaf;
6130       if ( !complexmode && has_evalf(delta,deltaf,1,context0) && is_positive(deltaf,context0)){
6131 	v.push_back(tmp);
6132 	return;
6133       }
6134       gen b_over_2=rdiv(b,plus_two,context0);
6135       if (b_over_2.type!=_FRAC){
6136 	delta=a*c-b_over_2*b_over_2;
6137 	gen un=plus_one;
6138 	if (is_positive(delta,context0)){
6139 	  un=cst_i;
6140 	  delta=-delta;
6141 	}
6142 	vecteur vv(makevecteur(plus_one,rdiv(algebraic_EXTension(makevecteur(un,b_over_2),makevecteur(plus_one,zero,delta)),a,context0)));
6143 	v.push_back(poly12polynome(vv,1));
6144 	vv=makevecteur(1,algebraic_EXTension(makevecteur(-un,b_over_2),makevecteur(plus_one,zero,delta))/a);
6145 	v.push_back(a*poly12polynome(vv,1));
6146       }
6147       else {
6148 	gen un=plus_one;
6149 	if (is_positive(delta,context0)){
6150 	  un=cst_i;
6151 	  delta=-delta;
6152 	}
6153 	vecteur vv(makevecteur(plus_one,rdiv(algebraic_EXTension(makevecteur(un,b),makevecteur(plus_one,zero,delta)),2*a,context0)));
6154 	v.push_back(poly12polynome(vv,1));
6155 	vv=makevecteur(1,rdiv(algebraic_EXTension(makevecteur(-un,b),makevecteur(plus_one,zero,delta)),2*a,context0));
6156 	v.push_back(a*poly12polynome(vv,1));
6157       }
6158     }
6159   }
6160 
cfactor(const polynome & p,gen & an,factorization & f,bool with_sqrt,gen & extra_div)6161   bool cfactor(const polynome & p, gen & an,factorization & f,bool with_sqrt,gen &extra_div){
6162     an=p.coord.front().value;
6163     if (has_num_coeff(p) && p.dim==1){
6164       vectpoly w;
6165       if (!sqfffactor(p,w,false,false,true))
6166 	return false;
6167       vectpoly::const_iterator itw=w.begin(),itwend=w.end();
6168       for (;itw!=itwend;++itw)
6169 	f.push_back(facteur<polynome>(*itw,1));
6170       return true;
6171     }
6172     factorization fsqff=sqff(p);
6173     // factorization of each factor of fsqff
6174     factorization fz;
6175     factorization::const_iterator it=fsqff.begin(),itend=fsqff.end();
6176     for (;it!=itend;++it){
6177       polynome pcur=it->fact;
6178       int mult=it->mult;
6179       int d=pcur.lexsorted_degree();
6180       if (!d)
6181 	continue;
6182       if (d==1){
6183 	an=rdiv(an,pow(pcur.coord.front().value,gen(mult),context0),context0);
6184 	f.push_back(facteur<polynome>(pcur,mult));
6185 	continue;
6186       }
6187       // make a polynomial with 1 more variable (i)
6188       polynome p_y(im(pcur).untrunc1(1)+re(pcur).untrunc1());
6189       polynome p_mini(p_y.dim);
6190       p_mini.coord.push_back(monomial<gen>(1,1,p_y.dim));
6191       p_mini=p_mini.multiplydegrees(2);
6192       p_mini.coord.push_back(monomial<gen>(1,0,p_y.dim));
6193       int k;
6194       polynome Gtry;
6195       if (!algfactor(p_y,p_mini,k,fz,false,extra_div,Gtry))
6196 	return false;
6197       factorization::const_iterator f_it=fz.begin(),f_itend=fz.end();
6198       for (;f_it!=f_itend;++f_it){
6199 	if (k){ // shift f_it->fact
6200 	  vecteur v;
6201 	  polynome2poly1(f_it->fact,1,v);
6202 	  gen decal=polynome(gen(0,k),f_it->fact.dim-1);
6203 	  v=taylor(v,decal);
6204 	  poly12polynome(v,1,pcur,f_it->fact.dim);
6205 	  pcur=gcd(pcur,p);
6206 	}
6207 	else
6208 	  pcur=gcd(f_it->fact,p);
6209 	an=rdiv(an,pow(pcur.coord.front().value,gen(mult),context0),context0);
6210 	vectpoly tmpv;
6211 	addtov(pcur,tmpv,with_sqrt,true);
6212 	f.push_back(facteur<polynome>(tmpv[0],mult));
6213 	if (tmpv.size()==2)
6214 	  f.push_back(facteur<polynome>(tmpv[1],mult));
6215       }
6216     }
6217     return true;
6218   }
6219 
6220   // factorize a square-free univariate polynomial
sqfffactor(const polynome & p,vectpoly & v,bool with_sqrt,bool test_composite,bool complexmode)6221   bool sqfffactor(const polynome &p, vectpoly & v,bool with_sqrt,bool test_composite,bool complexmode){
6222     if (debug_infolevel>5)
6223       CERR << "Begin sqfffactor" << p << '\n';
6224     // test if p has a numeric coeff
6225     if (has_num_coeff(p)){
6226       vecteur w=polynome2poly1(p,1);
6227       w=proot(w);
6228       if (is_undef(w))
6229 	return false;
6230       const_iterateur it=w.begin(),itend=w.end();
6231       polynome res(1),res2(1);
6232       res.coord.push_back(monomial<gen>(1,index_t(1,1)));
6233       res2.coord.push_back(monomial<gen>(1,index_t(1,2)));
6234       for (;it!=itend;++it){
6235 	polynome copie(1);
6236 	gen impart=im(*it,context0);
6237 	if (!complexmode && !is_zero(impart) && (it+1)!=itend ){
6238 	  copie = res2;
6239 	  gen repart=re(*it,context0);
6240 	  copie.coord.push_back(monomial<gen>(-2*repart,index_t(1,1)));
6241 	  copie.coord.push_back(monomial<gen>(repart*repart+impart*impart,index_t(1,0)));
6242 	  ++it;
6243 	}
6244 	else {
6245 	  copie = res;
6246 	  if (!is_zero(*it))
6247 	    copie.coord.push_back(monomial<gen>(-*it,index_t(1,0)));
6248 	}
6249 	v.push_back(copie);
6250       }
6251       return true;
6252     }
6253     int d;
6254     // special speedup for x^n +/- 1
6255     if (p.coord.size()==2 && p.coord.front().value==1 && is_zero(p.coord.back().index.iref())){
6256       d=p.lexsorted_degree();
6257       if (p.coord.back().value==-1){
6258 	// product of cyclotomic(n) where n divides d
6259 	gen dd=idivis(d,context0);
6260 	if (dd.type==_VECT){
6261 	  const_iterateur it=dd._VECTptr->begin(),itend=dd._VECTptr->end();
6262 	  for (;it!=itend;++it){
6263 	    if (with_sqrt){
6264 	      if (it->val==5 || it->val==10){
6265 		gen e=algebraic_EXTension(makevecteur(1,0),makevecteur(1,0,-5));
6266 		gen f=it->val==5?1:-1;
6267 		addtov(poly12polynome(makevecteur(1,(f-e)/2,1),1),v,false,false);
6268 		addtov(poly12polynome(makevecteur(1,(f+e)/2,1),1),v,false,false);
6269 		continue;
6270 	      }
6271 	      if (it->val==8){
6272 		gen e=algebraic_EXTension(makevecteur(1,0),makevecteur(1,0,-2));
6273 		addtov(poly12polynome(makevecteur(1,e,1),1),v,false,false);
6274 		addtov(poly12polynome(makevecteur(1,-e,1),1),v,false,false);
6275 		continue;
6276 	      }
6277 	    }
6278 	    polynome tmp=poly12polynome(cyclotomic(it->val),1);
6279 	    addtov(tmp,v,with_sqrt,complexmode);
6280 	  }
6281 	  return true;
6282 	}
6283       }
6284       if (d%4==0 && with_sqrt){
6285 	gen e=algebraic_EXTension(makevecteur(1,0),makevecteur(1,0,-2));
6286 	gen an=1,extra_div=1;
6287 	factorization f;
6288 	polynome p_content(p.dim);
6289 	if (ext_factor(p,e,an,p_content,f,complexmode,extra_div) && an==1 && extra_div==1){
6290 	  for (size_t i=0;i<f.size();++i){
6291 	    v.push_back(f[i].fact);
6292 	  }
6293 	  return true;
6294 	}
6295       }
6296       if (p.coord.back().value==1){
6297 	// product of cyclotomic(n) where n divides 2d and does not divide d
6298 	gen dd=_minus(makesequence(idivis(2*d,context0),idivis(d,context0)),context0);
6299 	if (dd.type==_VECT){
6300 	  const_iterateur it=dd._VECTptr->begin(),itend=dd._VECTptr->end();
6301 	  for (;it!=itend;++it){
6302 	    polynome tmp=poly12polynome(cyclotomic(it->val),1);
6303 	    addtov(tmp,v,with_sqrt,complexmode);
6304 	  }
6305 	  return true;
6306 	}
6307       }
6308     }
6309     // find the gcd of the degrees of *it
6310     if (test_composite)
6311       d=p.gcddeg(0);
6312     else
6313       d=1;
6314     if (debug_infolevel>5)
6315       CERR << "sqfffactor gcddeg " << d << '\n';
6316     if (d<=1){
6317       // find linear factors now!
6318       environment * env=new environment;
6319       polynome temp(1);
6320       int ithprime=1;
6321       int bound=linearfind(p,env,temp,v,ithprime);
6322       if (bound==0){
6323 #ifndef NO_STDEXCEPT
6324 	setsizeerr();
6325 #endif
6326 	return false;
6327       }
6328       // if degree of temp<=3, we are finished since not irred -> one fact
6329       // has degree 1 (hence found previously)
6330       int tempdeg=temp.lexsorted_degree();
6331       if (debug_infolevel>5)
6332 	CERR << "sqfffactor after linearfind " << temp << '\n';
6333       if (tempdeg<bound){
6334 	if (tempdeg)
6335 	  addtov(temp,v,with_sqrt,complexmode);
6336       }
6337       else {
6338 	// find other factors
6339 	vectpoly w;
6340 	int signe=1;
6341 	if (is_positive(-temp.coord.front()))
6342 	  signe=-1;
6343 	if (!factorunivsqff(temp,env,w,ithprime,(debug_infolevel>1?debug_infolevel:0),MODFACTOR_PRIMES)){
6344 #ifndef NO_STDEXCEPT
6345 	  setsizeerr();
6346 #endif
6347 	  return false;
6348 	}
6349 	vectpoly::const_iterator itw=w.begin(),itwend=w.end();
6350 	for (;itw!=itwend;++itw){
6351 	  addtov(*itw,v,with_sqrt,complexmode);
6352 	}
6353 	if (signe==-1)
6354 	  v.back()=-v.back();
6355       }
6356       delete env;
6357     }
6358     else { // gcddeg!=1, take the largest divisor of d
6359       //if (p.coord.size()==2){
6360       gen dd(d);
6361       vector<nfactor> nv(trivial_n_factor(dd));
6362       if (dd==gen(1))
6363 	d=nv[nv.size()-1].fact.to_int();
6364       else
6365 	d=dd.to_int();
6366       //}
6367       // use x^d as new variable, divide every degree by d
6368       if (d==p.lexsorted_degree())
6369 	return sqfffactor(p,v,with_sqrt,false,complexmode);
6370       polynome q(p.dividedegrees(d));
6371       vectpoly w;
6372       // IMPROVE: if we factor allowing 2nd order poly roots
6373       // we could factor bisquare poly
6374       // BUT that requires converting the roots to internal form
6375       if (!sqfffactor(q,w,false,true,complexmode))
6376 	return false;
6377       vectpoly::const_iterator itw=w.begin(),itwend=w.end();
6378       for (;itw!=itwend;++itw){
6379 	if (!sqfffactor(itw->multiplydegrees(d),v,with_sqrt,false,complexmode))
6380 	  return false;
6381       }
6382     }
6383     return true;
6384   }
6385 
sqff(const polynome & p)6386   factorization sqff(const polynome &p ){
6387     factorization f=Tsqff_char0<gen>(p);
6388     // take care of cst coefficients
6389     if (!p.coord.empty()){
6390       gen p0=p.coord.front().value;
6391       for (unsigned i=0;i<f.size();++i){
6392 	p0=p0/pow(f[i].fact.coord.front().value,f[i].mult,context0);
6393       }
6394       if (!is_one(p0)){
6395 	if (f.empty() || f[0].mult!=1)
6396 	  f.insert(f.begin(),facteur<polynome>(polynome(p0,p.dim),1));
6397 	else
6398 	  f[0].fact = p0*f[0].fact;
6399       }
6400     }
6401     return f;
6402   }
6403 
sqff_evident_primitive(const polynome & pp,factorization & f,bool with_sqrt,bool complexmode)6404   static bool sqff_evident_primitive(const polynome & pp,factorization & f,bool with_sqrt,bool complexmode){
6405     // first square-free factorization
6406 
6407 #if 0 // Cette version ne marche pas it->fact plus bas renvoie un vecteur vide.. ou quelquechose comme ca..
6408    const factorization & sqff_f = has_num_coeff(pp)?factorization(1,facteur< polynome >(pp,1)):sqff(pp);
6409 #else // celle la, plus ancienne, marche...
6410     factorization sqff_f;
6411     if (has_num_coeff(pp))
6412       sqff_f.push_back(facteur< polynome >(pp,1));
6413     else
6414       sqff_f=sqff(pp);
6415 #endif
6416     f.clear();
6417     if (pp.dim!=1){
6418       f=sqff_f;
6419       return true;
6420     }
6421     factorization::const_iterator it=sqff_f.begin();
6422     factorization::const_iterator itend=sqff_f.end();
6423     vectpoly v;
6424     for (;it!=itend;++it){
6425       v.clear();
6426       if (!sqfffactor(it->fact,v,with_sqrt,true,complexmode))
6427 	return false;
6428       f.reserve(f.size()+v.size());
6429       vectpoly::const_iterator itv=v.begin(),itvend=v.end();
6430       for (;itv!=itvend;++itv)
6431 	f.push_back(facteur<polynome>(*itv,it->mult));
6432     }
6433     return true;
6434   }
6435 
sqff_evident(const polynome & p,factorization & f,bool with_sqrt,bool complexmode)6436   bool sqff_evident(const polynome & p,factorization & f,bool with_sqrt,bool complexmode){
6437     // first make p primitive
6438     polynome pp=p/lgcd(p);
6439     return sqff_evident_primitive(pp,f,with_sqrt,complexmode);
6440   }
6441 
6442   /* Factorization of sqff unitary polynomial with variables in reverse order
6443      Return number of factors, -1 if not successful
6444      Might be called if polynomial is not unitary, but there is no
6445      proof that unlimited tries succeed in this case */
unitaryfactor(polynome & unitaryp,vectpoly & f,bool with_sqrt,bool complexmode)6446   static int unitaryfactor(polynome & unitaryp, vectpoly & f,bool with_sqrt,bool complexmode){
6447     int dd=unitaryp.degree(unitaryp.dim-1);
6448     if (!dd)
6449       return 0; // unitaryp is cst w.r.t. x
6450     if (dd==1){
6451       f.push_back(unitaryp);
6452       unitaryp=unitaryp/unitaryp;
6453       return 1;
6454     }
6455     if (unitaryp.dim==1){
6456       factorization ff;
6457       if (!sqff_evident(unitaryp,ff,with_sqrt,complexmode))
6458 	return -1;
6459       if (f.empty())
6460 	f.reserve(ff.size());
6461       factorization::const_iterator ff_it=ff.begin(),ff_end=ff.end();
6462       for (;ff_it!=ff_end;++ff_it)
6463 	f.push_back(ff_it->fact);
6464       return int(ff.size());
6465     }
6466     ppz(unitaryp); // remove content
6467     gen n_2(2),np,n_73794(73794),n_27011(27011);
6468     polynome quo(unitaryp.dim),rem(unitaryp.dim);
6469     if (!listmax(unitaryp,np))
6470       return 0;
6471     gen x0(n_2*np+n_2);
6472     int ntry=0;
6473     while (unitaryp.lexsorted_degree()){
6474       ntry++;
6475       if (ntry>GCDHEU_MAXTRY)
6476 	return 0;
6477       // find evaluation point such that evaluated poly is sqff
6478       // pz is unitary w.r.t. last var hence has same degree and is primitive
6479       polynome pz(unitaryp(x0));
6480       while (gcd(pz.derivative(),pz).lexsorted_degree()){
6481 	x0=x0+gen(1);
6482 	pz=unitaryp(x0);
6483       }
6484       // factorization of pz
6485       vectpoly fz;
6486       int nf=unitaryfactor(pz,fz,with_sqrt,complexmode);
6487       if (nf==-1)
6488 	return nf;
6489       if (!nf)
6490 	return int(f.size());
6491       if (nf==1) {
6492 	f.push_back(unitaryp);
6493 	unitaryp=polynome(monomial<gen>(gen(1),0,unitaryp.dim));
6494 	return int(f.size());
6495       }
6496       // factorization fz into factorization f
6497       vectpoly::iterator f_it=fz.begin(),f_itend=fz.end();
6498       for (;f_it!=f_itend;++f_it){
6499 	*f_it=pzadic(*f_it,x0);
6500 	// try division, each factor found is necessarily irreducible
6501 	if ( (unitaryp.TDivRem1(*f_it,quo,rem)) && (rem.coord.empty())){
6502 	  unitaryp=quo;
6503 	  f.push_back(*f_it);
6504 	}
6505       }
6506       x0=iquo(x0*n_73794,n_27011); // for the next try, if necessary
6507     }
6508     // factorize the cst term
6509     vectpoly fz;
6510     polynome tmp(unitaryp.trunc1());
6511     int nf=unitaryfactor(tmp,fz,with_sqrt,complexmode);
6512     if (nf==-1)
6513       return nf;
6514     if (!nf)
6515       return int(f.size());
6516     if (nf==1){
6517       f.push_back(unitaryp);
6518       unitaryp=polynome(monomial<gen>(gen(1),0,unitaryp.dim));
6519       return int(f.size());
6520     }
6521     vectpoly::iterator f_it=fz.begin(),f_itend=fz.end();
6522     for (;f_it!=f_itend;++f_it)
6523       f.push_back(f_it->untrunc1());
6524     unitaryp=polynome(monomial<gen>(gen(1),0,unitaryp.dim));
6525     return int(f.size());
6526   }
6527 
unitarize(const polynome & pcur,polynome & unitaryp,polynome & an)6528   void unitarize(const polynome &pcur, polynome &unitaryp, polynome & an){
6529     an=firstcoeff(pcur).trunc1();
6530     if (is_one(an)){
6531       unitaryp=pcur;
6532       return;
6533     }
6534     monomial_v::const_iterator it=pcur.coord.begin();
6535     monomial_v::const_iterator itend=pcur.coord.end();
6536     polynome curanpow(pow(an,0));
6537     int savpow=it->index.front();
6538     unitaryp=pow(polynome(monomial<gen>(gen(1),1,pcur.dim)),savpow);
6539     savpow--;
6540     int newpow;
6541     Tnextcoeff<gen>(it,itend); // ++it;
6542     for (;it!=itend;){
6543       newpow=it->index.front();
6544       polynome an_1=Tnextcoeff<gen>(it,itend);
6545       curanpow=curanpow*pow(an,savpow-newpow);
6546       unitaryp=unitaryp+(an_1*curanpow).untrunc1(newpow);
6547       savpow=newpow;
6548     }
6549   }
6550 
ununitarize(const polynome & unitaryp,const polynome & an)6551   polynome ununitarize(const polynome & unitaryp, const polynome & an){
6552     if (is_one(an))
6553       return unitaryp;
6554     monomial_v::const_iterator it=unitaryp.coord.begin();
6555     monomial_v::const_iterator itend=unitaryp.coord.end();
6556     int curpow;
6557     polynome ppush(unitaryp.dim);
6558     for (;it!=itend;){
6559       curpow=it->index.front();
6560       polynome an_1=Tnextcoeff<gen>(it,itend);
6561       ppush=ppush+(an_1*pow(an,curpow)).untrunc1(curpow);
6562     }
6563     return ppush/lgcd(ppush);
6564   }
6565 
do_factor_hensel(const polynome & p,polynome & p_primit,polynome & p_content,factorization & f,bool isprimitive,bool with_sqrt,bool complexmode,const gen & divide_an_by,gen & extra_div,bool hensel_only)6566   static bool do_factor_hensel(const polynome &p,polynome& p_primit,polynome & p_content,factorization & f,bool isprimitive,bool with_sqrt,bool complexmode,const gen & divide_an_by,gen & extra_div,bool hensel_only){
6567     if (p.dim==1){
6568       // FIXME: if p_primit has num coeffs, we must check the leading coeff
6569       // and adjust p_content
6570       if (has_num_coeff(p_primit)){
6571 	gen an=p_primit.coord.front().value;
6572 	p_content=an*p_content;
6573 	vector< monomial<gen> >::iterator it=p_primit.coord.begin(),itend=p_primit.coord.end();
6574 	for (;it!=itend;++it)
6575 	  it->value=evalf(it->value/an,1,context0);
6576       }
6577       return sqff_evident_primitive(p_primit,f,with_sqrt,complexmode);
6578     }
6579     // extract powers of indeterminates
6580     index_t mindeg=p_primit.coord.back().index.iref();
6581     vector< monomial<gen> >::const_iterator pt=p_primit.coord.begin(),ptend=p_primit.coord.end();
6582     for (;pt!=ptend;++pt){
6583       mindeg=index_min(mindeg,pt->index.iref());
6584       if (is_zero(mindeg))
6585 	break;
6586     }
6587     // square-free factorization
6588     factorization fsqff;
6589     if (!is_zero(mindeg)){
6590       p_primit=p_primit.shift(-mindeg);
6591       fsqff=sqff(p_primit);
6592       for (int i=0;i<p.dim;++i){
6593 	if (mindeg[i])
6594 	  f.push_back(facteur<polynome>(monomial<gen>(1,i+1,p.dim),mindeg[i]));
6595       }
6596     }
6597     else
6598       fsqff=sqff(p_primit);
6599     // factorization of each factor of fsqff
6600     /*
6601       First of course square free factorization, then try a few (2) random values for all indeterminates except the first one, for a fast check of irreducibility. If not, lift the equality in one variable
6602       P(x,0,...0)=product P_i(x,0,...,0)
6603       more precisely, one must take care of the leading coefficient, hence lift
6604       P*lcoeff(P)^(#nfactors-1)=product P_i
6605       where in P_i the leading coefficient is replaced by lcoeff(P).
6606       In order to avoid densification (if lcoeff(P) has many coefficients), I make a bivariate factorization, this way instead of using lcoeff(P) for every P_i, I'm using a divisor of lcoeff(P). It's a little different from what is describe in the thesis of Bernardin (I don't make polynomial rational reconstructions for example).
6607       There is also a try to do sparse factorization before.
6608       If Hensel lift does not work (for example P(x,0...0) loose degree or has non square-free factors), I'm using "heuristic factorization", i.e. evaluate P at x>=2 linfnorm(P)+2, factor this polynomial, reconstruct factors (using x as basis and symmetric remainder) and check division, if remainder is 0 an irreducible factor has been found, otherwise try with a larger value of x.
6609       The corresponding code slices are in ezgcd.cc try_sparse_factor and try_hensel_lift_factor, and do_factor in gausspol.cc.
6610     */
6611     factorization::const_iterator it=fsqff.begin(),itend=fsqff.end();
6612     for (;it!=itend;++it){
6613       polynome pcur=it->fact;
6614       int mult=it->mult;
6615       if (has_num_coeff(pcur)){
6616 	f.push_back(facteur<polynome>(pcur,mult));
6617 	continue;
6618       }
6619       // try first 2 good evaluations in case pcur is irreducible
6620       vecteur b(pcur.dim-1),b0;
6621       factorization v,v0;
6622       polynome Fb(1),Gb(1),F0;
6623       int essai,nfactbound=RAND_MAX;
6624       for (essai=0;essai<2;++essai){
6625 	if (essai)
6626 	  b=vranm(pcur.dim-1,0,0); // find another random point
6627 	find_good_eval(pcur,pcur,Fb,Gb,b,(debug_infolevel>=2));
6628 	factor(Fb,Gb,v,false,false,false,1,extra_div);
6629 	if (!essai){
6630 	  F0=Fb;
6631 	  v0=v;
6632 	  b0=b;
6633 	}
6634 	if ( (v.size()==1) && (v.front().mult==1) )
6635 	  break;
6636 	factorization::const_iterator it=v.begin(),itend=v.end();
6637 	int nfact=0;
6638 	for (;it!=itend;++it)
6639 	  nfact += it->mult;
6640 	if (0 && essai && nfactbound>nfact){
6641 	  nfactbound=nfact;
6642 	  F0=Fb;
6643 	  v0=v;
6644 	  b0=b;
6645 	}
6646 	nfactbound=giacmin(nfactbound,nfact);
6647       }
6648       if (essai<2){
6649 	f.push_back(facteur<polynome>(pcur,mult));
6650 	continue;
6651       }
6652       // check if pcur is a homogeneous polynomial
6653       if (sum_degree(pcur.coord.back().index)){
6654 	int xdeg=sum_degree(pcur.coord.back().index);
6655 	vector< monomial<gen> >::iterator it=pcur.coord.begin(),itend=pcur.coord.end();
6656 	for (;it!=itend;++it){
6657 	  if (sum_degree(it->index)!=xdeg){
6658 	    break;
6659 	  }
6660 	}
6661 	if (it==itend){
6662 	  // set x[j]=x[0]*x[j] for all vars, divide by x[0]^xdeg,
6663 	  // remove old x[0] variable
6664 	  polynome pcurh(pcur.trunc1());
6665 	  pcurh.tsort();
6666 	  // factor it
6667 	  polynome pcur_cont;
6668 	  factorization pcur_f,ppcur_f;
6669 	  do_factor(pcurh,pcur_cont,pcur_f,false,with_sqrt,complexmode,1,extra_div);
6670 	  // factorize (recursivly) pcur_cont
6671 	  for (int innerdim=1;innerdim<pcur.dim && !pcur_cont.coord.empty() && sum_degree(pcur_cont.coord.front().index);++innerdim){
6672 	    polynome pp=pcur_cont.trunc1();
6673 	    do_factor(pp,pcur_cont,ppcur_f,false,with_sqrt,complexmode,1,extra_div);
6674 	    for (unsigned i=0;i<ppcur_f.size();++i){
6675 	      polynome tmp(ppcur_f[i].fact.untrunc1());
6676 	      for (int j=1;j<innerdim;++j){
6677 		tmp=tmp.untrunc1();
6678 	      }
6679 	      pcur_f.push_back(facteur<polynome>(tmp,ppcur_f[i].mult));
6680 	    }
6681 	  }
6682 	  if (pcur_f.size()==1){
6683 	    f.push_back(facteur<polynome>(pcur,mult));
6684 	    continue;
6685 	  }
6686 	  // for each factor multiply by x[0]^degree in x[j] of factor,
6687 	  // and set x[j]=x[j]/x[0], and put in v
6688 	  for (unsigned i=0;i<pcur_f.size();++i){
6689 	    polynome & P=pcur_f[i].fact;
6690 	    it=P.coord.begin(); itend=P.coord.end();
6691 	    int jdeg=0;
6692 	    for (;it!=itend;++it)
6693 	      jdeg=giacmax(jdeg,sum_degree(it->index));
6694 	    it=P.coord.begin();
6695 	    for (;it!=itend;++it){
6696 	      index_t idx=it->index.iref();
6697 	      idx.insert(idx.begin(),jdeg-sum_degree(idx));
6698 	      it->index=idx;
6699 	    }
6700 	    P.tsort();
6701 	    P.dim=pcur.dim;
6702 	    // adjust sign
6703 	    if (is_strictly_positive(-P.coord.front().value,context0))
6704 	      P=-P;
6705 	    f.push_back(facteur<polynome>(P,mult));
6706 	  }
6707 	  continue;
6708 	} // end homogeneous poly
6709       } // end if (sum_degrees(...)
6710       if (try_sparse_factor(pcur,v,mult,f))
6711 	continue;
6712       if (try_sparse_factor_bi(pcur,mult,f))
6713 	continue;
6714       /* Try Hensel lift factorization */
6715       bool hensel_factored=false;
6716       for (unsigned hensel_try=0;hensel_try<5;++hensel_try){
6717 	gen lm;
6718 	if (!listmax(p,lm))
6719 	  lm=100;
6720 	if (p.dim>2 && !is_zero(b0) && is_greater(lm,10,context0)){
6721 	  int b0d=int(b0.size());
6722 	  // search a smaller b
6723 	  for (int essai=0;essai<3;++essai){
6724 	    for (int i=0;i<b0d;++i){
6725 	      //b[i]=1+iquo(rand(),RAND_MAX/3);
6726 	      b[i]=1+iquo(giac_rand(context0),RAND_MAX/4);
6727 	    }
6728 	    if (find_good_eval(pcur,pcur,Fb,Gb,b,(debug_infolevel>=2))){
6729 	      b0=b;
6730 	      break;
6731 	    }
6732 	  }
6733 	  // translate
6734 	  vecteur vb0(b0d+1),vb1(b0d+1),lv(b0d+1);
6735 	  lv[0]=gen("x0",context0);
6736 	  vb0[0]=sym2r(lv[0],lv,context0);
6737 	  vb1[0]=vb0[0];
6738 	  for (int i=1;i<=b0d;i++){
6739 	    lv[i]=gen("x"+print_INT_(i),context0);
6740 	    vb0[i]=sym2r(lv[i]+b0[i-1],lv,context0);
6741 	    vb1[i]=sym2r(lv[i]-b0[i-1],lv,context0);
6742 	  }
6743 	  gen pb=peval(pcur,vb0,0,false),num,den;
6744 	  fxnd(pb,num,den);
6745 	  if (num.type!=_POLY){
6746 #ifndef NO_STDEXCEPT
6747 	    setsizeerr();
6748 #endif
6749 	    return false;
6750 	  }
6751 	  polynome ptrans=*num._POLYptr;
6752 	  factorization ftrans;
6753 	  b=vecteur(b.size());
6754 	  find_good_eval(ptrans,ptrans,Fb,Gb,b,(debug_infolevel>=2));
6755 	  if (is_zero(b)){
6756 	    factor(Fb,Gb,v0,false,false,false,1,extra_div);
6757 	    if (int(v0.size())<2*nfactbound && try_hensel_lift_factor(ptrans,Fb,v0,mult,ftrans)){
6758 	      factorization::const_iterator it=ftrans.begin(),itend=ftrans.end();
6759 	      for (;it!=itend;++it){
6760 		pb=peval(it->fact,vb1,0,false);
6761 		fxnd(pb,num,den);
6762 		if (num.type!=_POLY){
6763 #ifndef NO_STDEXCEPT
6764 		  setsizeerr();
6765 #endif
6766 		  return false;
6767 		}
6768 		f.push_back(facteur<polynome>(*num._POLYptr,it->mult));
6769 	      }
6770 	      hensel_factored=true;
6771 	      break; // break loop on hensel_try
6772 	    }
6773 	  }
6774 	}
6775       } // end loop on hensel_try
6776       if (hensel_factored)
6777 	continue;
6778       if (debug_infolevel)
6779 	CERR << CLOCK()*1e-6 << " hensel lift factor begin" << '\n';
6780       if (is_zero(b0) && int(v0.size())<2*nfactbound && try_hensel_lift_factor(pcur,F0,v0,mult,f)){
6781 	if (debug_infolevel)
6782 	  CERR << CLOCK()*1e-6 << " hensel lift factor success" << '\n';
6783 	continue;
6784       }
6785       if (debug_infolevel)
6786 	CERR << CLOCK()*1e-6 << " hensel lift factor failure" << '\n';
6787       if (hensel_only)
6788 	return false;
6789       /* Now try heuristic factorization then call unitaryfactor
6790 	 on each found factor */
6791       vectpoly fz;
6792       pcur.reverse();
6793       unitaryfactor(pcur,fz,false,false);
6794       pcur.reverse();
6795       vectpoly::iterator f_it=fz.begin(),f_itend=fz.end();
6796       for (;f_it!=f_itend;++f_it){
6797 	f_it->reverse();
6798 	// if an!=1, P(Y)=P(a_n*X) and divide by content
6799 	f.push_back(facteur<polynome>(*f_it,mult));
6800       }
6801       if (!is_one(pcur)){
6802 	/* now make polynomial unitary with respect to last var
6803 	   P(x)=a_n*x^n+...+a_0, x=X/a_n,
6804 	   P(x)=Q(X)=1/a_n^(n-1) * [ X^n+ a_{n-1}*a_n X^(n-1)+...+ a_0*a_n^{n-1}]
6805 	*/
6806 	fz.clear();
6807 	polynome unitaryp(p.dim),an(p.dim-1);
6808 	unitarize(pcur,unitaryp,an);
6809 	// rewrite variables in inverted order
6810 	unitaryp.reverse();
6811 	// and call unitaryfactor
6812 	if (unitaryfactor(unitaryp,fz,false,false)==-1)
6813 	  return false;
6814 	// rewrite back variables in initial order for each polynomial
6815 	// and push back factorization
6816 	f_it=fz.begin(),f_itend=fz.end();
6817 	for (;f_it!=f_itend;++f_it){
6818 	  f_it->reverse();
6819 	  // if an!=1, P(Y)=P(a_n*X) and divide by content
6820 	  f.push_back(facteur<polynome>(ununitarize(*f_it,an),mult));
6821 	}
6822       }
6823     }
6824     // adjust lcoeff
6825     if (!p_content.coord.empty()){
6826       gen lc(1);
6827       for (it=f.begin(),itend=f.end();it!=itend;++it){
6828 	lc=lc*pow(it->fact.coord.front().value,it->mult,context0);
6829       }
6830       p_content = p.coord.front().value/(p_content.coord.front().value*lc)*p_content;
6831     }
6832     return true;
6833   }
6834 
is_homogeneous(const polynome & p)6835   int is_homogeneous(const polynome & p){
6836     std::vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
6837     if (p.dim<2 || it==itend)
6838       return 0;
6839     int d=sum_degree(it->index);
6840     for (++it;it!=itend;++it){
6841       if (sum_degree(it->index)!=d)
6842 	return 0;
6843     }
6844     return d;
6845   }
6846 
homogeneize(polynome & p,int dhom)6847   bool homogeneize(polynome & p,int dhom){
6848     ++p.dim;
6849     std::vector< monomial<gen> >::iterator it=p.coord.begin(),itend=p.coord.end();
6850     for (;it!=itend;++it){
6851       int d=sum_degree(it->index);
6852       if (d>dhom)
6853 	return false;
6854       index_t i(it->index.begin(),it->index.end());
6855       i.push_back(dhom-d);
6856       it->index=i;
6857     }
6858     return true;
6859   }
6860 
do_factor(const polynome & p,polynome & p_content,factorization & f,bool isprimitive,bool with_sqrt,bool complexmode,const gen & divide_an_by,gen & extra_div)6861   static bool do_factor(const polynome &p,polynome & p_content,factorization & f,bool isprimitive,bool with_sqrt,bool complexmode,const gen & divide_an_by,gen & extra_div){
6862     // check for homogeneous polynomial -> 1 var less
6863     if (int dhom=is_homogeneous(p)){
6864       polynome phom(p);
6865       // remove last degree
6866       std::vector< monomial<gen> >::iterator it=phom.coord.begin(),itend=phom.coord.end();
6867       for (;it!=itend;++it){
6868 	it->index=index_t(it->index.begin(),it->index.end()-1);
6869       }
6870       phom.dim--;
6871       bool res=do_factor(phom,p_content,f,false,with_sqrt,complexmode,divide_an_by,extra_div);
6872       // rehomogeneize f
6873       factorization::iterator f_it=f.begin(),f_itend=f.end();
6874       for (;f_it!=f_itend;++f_it){
6875 	int d=f_it->fact.total_degree();
6876 	homogeneize(f_it->fact,d);
6877 	dhom -= d*f_it->mult;
6878       }
6879       homogeneize(p_content,dhom);
6880       return res;
6881     }
6882     f.clear();
6883     if (p.coord.empty()){
6884       p_content=p;
6885       return true;
6886     }
6887     polynome p_primit(p.dim);
6888     if (!isprimitive){
6889       p_content=lgcd(p);
6890       if (is_strictly_positive(-p.coord.front().value,context0) && is_strictly_positive(p_content.coord.front().value,context0))
6891 	p_content=-p_content;
6892       // p_primit=p/p_content;
6893       polynome unused;
6894       if (!divrem1(p,p_content,p_primit,unused,0,false)){
6895 	divrem1(p,p_content,p_primit,unused,0,true);
6896 	gen tmp(1);
6897 	lcmdeno(p_primit,tmp);
6898 	p_primit = tmp*p_primit;
6899 	extra_div=extra_div*tmp;
6900       }
6901     }
6902     else
6903       p_primit=p;
6904     p_content /= divide_an_by;
6905     if (is_one(p_primit))
6906       return true;
6907     if (p_primit.lexsorted_degree()==1){
6908       f.push_back(facteur<polynome>(p_primit,1));
6909       return true;
6910     }
6911     if (!is_zero(im(divide_an_by,0))) // || !is_zero(im(p_primit,context0)))
6912       complexmode=true;
6913     if (!p_content.coord.empty()){
6914       if (!complexmode && !is_zero(im(p_content.coord.front().value,0)))
6915 	complexmode=true;
6916       // check if one coeff is an alg. extension (only one is allowed)
6917       if (p_content.coord.front().value.type==_EXT){
6918 	gen an;
6919 	if (!ext_factor(p_primit,p_content.coord.front().value,an,p_content,f,complexmode,extra_div))
6920 	  return false;
6921 	p_content=an*p_content;
6922 	return true;
6923       }
6924     }
6925     if (divide_an_by.type==_EXT){
6926       gen an;
6927       if (!ext_factor(p_primit,divide_an_by,an,p_content,f,complexmode,extra_div))
6928 	return false;
6929       p_content=an*p_content;
6930       return true;
6931     }
6932     vector< monomial<gen> >::const_iterator ckalg_it=p.coord.begin(),ckalg_itend=p.coord.end();
6933     for (; ckalg_it!=ckalg_itend;++ckalg_it){
6934       if (p.dim>1 && (ckalg_it->value.type==_DOUBLE_ ||
6935 		      ckalg_it->value.type==_REAL ||
6936 		      ckalg_it->value.type==_FLOAT_ ||
6937 		      (ckalg_it->value.type==_CPLX && (ckalg_it->value._CPLXptr->type==_DOUBLE_ || (ckalg_it->value._CPLXptr+1)->type==_DOUBLE_))
6938 		      ) ){
6939 	// FIXME Prime terminal output
6940 	// CERR << "Factorization of multivariate polynomial with approx. coeffs not implemented. Please try with exact coefficients" << '\n';
6941 #if 1 // otherwise integrate(cos(x/2)**2/(x+sin(x)),x); failure
6942 	return false;
6943 #endif
6944       }
6945       if (ckalg_it->value.type==_USER){
6946 	ckalg_it->value._USERptr->polyfactor(p_primit,f);
6947 	return true;
6948       }
6949       if (ckalg_it->value.type==_EXT){
6950 	// Try Hensel lift for multivariate factorization if extension of degree>=3
6951 	if (p_primit.dim>1 && (ckalg_it->value._EXTptr+1)->type==_VECT
6952 	    //&& (ckalg_it->value._EXTptr+1)->_VECTptr->size()>3
6953 	    ){
6954 	  if (do_factor_hensel(p,p_primit,p_content,f,isprimitive,with_sqrt,complexmode,divide_an_by,extra_div,true))
6955 	    return true;
6956 	}
6957 	gen an;
6958 	if (!ext_factor(p_primit,ckalg_it->value,an,p_content,f,complexmode,extra_div))
6959 	  return false;
6960 	if (with_sqrt){
6961 	  factorization fz(f);
6962 	  f.clear();
6963 	  factorization::const_iterator f_it=fz.begin(),f_itend=fz.end();
6964 	  for (;f_it!=f_itend;++f_it){
6965 	    vectpoly tmpv;
6966 	    addtov(f_it->fact,tmpv,with_sqrt,complexmode);
6967 	    f.push_back(facteur<polynome>(tmpv[0],f_it->mult));
6968 	    if (tmpv.size()==2)
6969 	      f.push_back(facteur<polynome>(tmpv[1],f_it->mult));
6970 	  }
6971 	}
6972 	p_content=an*p_content;
6973 	return true;
6974       }
6975     }
6976     // check if polynomial coeff are embedded inside p
6977     for (ckalg_it=p.coord.begin(); ckalg_it!=ckalg_itend;++ckalg_it){
6978       if (ckalg_it->value.type==_POLY)
6979 	return poly_factor(p,ckalg_it->value._POLYptr->dim,p_content,f,with_sqrt,complexmode,extra_div);
6980     }
6981     // check if p has modular coeff
6982     for (ckalg_it=p.coord.begin(); ckalg_it!=ckalg_itend;++ckalg_it){
6983       if (ckalg_it->value.type==_MOD){
6984 	if ((ckalg_it->value._MODptr+1)->type!=_INT_)
6985 	  return false;
6986 	return mod_factor(p_primit,p_content,(ckalg_it->value._MODptr+1)->val,f);
6987       }
6988     }
6989     // check if one coefficient is complex
6990     if (complexmode || !is_zero(im(p))){
6991       gen an;
6992       bool res=cfactor(p_primit,an,f,with_sqrt,extra_div);
6993       if (!res)
6994 	return false;
6995       p_content=an*p_content;
6996       return true;
6997     }
6998     return do_factor_hensel(p,p_primit,p_content,f,isprimitive,with_sqrt,complexmode,divide_an_by,extra_div,false);
6999   }
7000 
polynome_less(const polynome & f,const polynome & g)7001   bool polynome_less(const polynome & f,const polynome & g){
7002     unsigned fs=unsigned(f.coord.size()),gs=unsigned(g.coord.size());
7003     if (fs!=gs)
7004       return fs<gs;
7005     if (!gs)
7006       return false;
7007     vector< monomial<gen> > ::const_iterator it=f.coord.begin(),jt=g.coord.begin(),itend=f.coord.end();
7008     for (;it!=itend;++it,++jt){
7009       if (it->index!=jt->index)
7010 	return !lex_is_greater(it->index.iref(),jt->index.iref()); // (jt->index <= it->index);
7011       if (it->value!=jt->value){
7012 	gen a=evalf_double(it->value,1,context0),b=evalf_double(jt->value,1,context0);
7013 	if (a.type==_DOUBLE_ && b.type==_DOUBLE_)
7014 	  return a._DOUBLE_val<b._DOUBLE_val;
7015 	return it->value.islesscomplexthan(jt->value);
7016       }
7017     }
7018     return false;
7019   }
7020 
7021   struct facteur_polynome_sort_t {
facteur_polynome_sort_tgiac::facteur_polynome_sort_t7022     facteur_polynome_sort_t(){}
operator ()giac::facteur_polynome_sort_t7023     bool operator ()(const facteur<polynome> & f,const facteur<polynome> & g){
7024       return polynome_less(f.fact,g.fact);
7025     }
7026   };
7027 
factor(const polynome & p,polynome & p_content,factorization & f,bool isprimitive,bool with_sqrt,bool complexmode,const gen & divide_an_by,gen & extra_div)7028   bool factor(const polynome &p,polynome & p_content,factorization & f,bool isprimitive,bool with_sqrt,bool complexmode,const gen & divide_an_by,gen & extra_div){
7029     bool res=do_factor(p,p_content,f,isprimitive,with_sqrt,complexmode,divide_an_by,extra_div);
7030 #if 1 // ndef EMCC // does not work for emscripten, don't know why...
7031     // sort f
7032     sort(f.begin(),f.end(),facteur_polynome_sort_t());
7033 #endif
7034     return res;
7035   }
7036 
operator <(const polynome & f,const polynome & g)7037   bool operator < (const polynome & f,const polynome & g){
7038     return polynome_less(f,g);
7039   }
7040 
operator <(const facteur<polynome> & f,const facteur<polynome> & g)7041   bool operator < (const facteur<polynome> & f,const facteur<polynome> & g){
7042     const polynome & fp=f.fact;
7043     const polynome & gp=g.fact;
7044     return fp<gp;
7045   }
7046 
is_positive(const polynome & p)7047   bool is_positive(const polynome & p){
7048     if (p.coord.empty())
7049       return true;
7050     return (is_positive(p.coord.front().value,context0));
7051   }
7052 
partfrac(const polynome & num_,const polynome & den_,const vector<facteur<polynome>> & v_,vector<pf<gen>> & pfdecomp,polynome & ipnum,polynome & ipden,bool rational)7053   void partfrac(const polynome & num_, const polynome & den_, const vector< facteur< polynome > > & v_ , vector < pf <gen> > & pfdecomp, polynome & ipnum, polynome & ipden,bool rational ){
7054     polynome num(num_),den(den_);
7055     vector< facteur< polynome > > v(v_);
7056     vector< facteur< polynome > >::iterator jt=v.begin(),jtend=v.end();
7057     if (jt==jtend){
7058       ipnum=num_;
7059       ipden=den_;
7060       return;
7061     }
7062     for (;jt!=jtend;++jt){
7063       gen tmp(1);
7064       lcmdeno(jt->fact,tmp);
7065       if (!is_one(tmp)){
7066 	jt->fact=tmp*jt->fact;
7067 	tmp=pow(tmp,jt->mult,context0);
7068 	num=tmp*num;
7069 	den=tmp*den;
7070       }
7071     }
7072     // check that all mult == 1 and deg<=2
7073     // later will split in 2 parts, 1st having this property
7074     vector< facteur< polynome > >::const_iterator it=v.begin(),itend=v.end();
7075     pfdecomp.reserve(itend-it);
7076     for (;it!=itend;++it){
7077       if (it->mult!=1 || it->fact.lexsorted_degree()>2)
7078 	break;
7079     }
7080     if (!rational || it!=itend){
7081       Tpartfrac(num,den,v,pfdecomp,ipnum,ipden);
7082       return;
7083     }
7084     // conditions met
7085     // compute integral part
7086     int dim=num.dim;
7087     polynome rem(dim);
7088     num.TPseudoDivRem(den,ipnum,rem,ipden);
7089     // for degree==1 : N/(P*Q)= (N mod P)/(Q mod P) / P + ...
7090     // for P of degree==2, P=a*x^2+b*x+c, D=P*Q, N mod P = n1*x+n2
7091     // Q mod P = q1*x+q2, then N/(D*P)=v/P+...
7092     // where v=1/(q2*(a*q2-b*q1)+c*q1^2)*(n2*(a*q2-q1*b)+q1*n1*c+(-q1*n2+q2*n1)*a*x)
7093     it = v.begin();
7094     if (itend-it==1){
7095       polynome nums(rem), dens(den*ipden);
7096       TsimplifybyTlgcd(nums,dens);
7097       pfdecomp.push_back(pf<gen>(nums,dens,it->fact,it->mult));
7098       return;
7099     }
7100     polynome nmodp(dim),nmodpden(dim),q(dim),qmodp(dim),qmodpden(dim),quo(dim),tmp;
7101     for (;it!=itend;++it){
7102       const polynome & P =it->fact;
7103       if (P.lexsorted_degree()==0) continue;
7104       rem.TPseudoDivRem(P,quo,nmodp,nmodpden); // nmodpden*num=P*quo+nmodp -> num mod P = nmodp/nmodpden
7105       nmodpden=nmodpden*ipden;
7106       den.TDivRem(P,q,tmp,false);
7107       q.TPseudoDivRem(P,quo,qmodp,qmodpden); // qmodpden*q=P*quo+qmodp -> q mod P = qmodp/qmodpden
7108       if (P.lexsorted_degree()==1){
7109 	simplify(qmodpden,nmodpden);
7110 	simplify(nmodp,qmodp);
7111 	pfdecomp.push_back(pf<gen>(nmodp*qmodpden,qmodp*nmodpden*P,P,1));
7112 	continue;
7113       }
7114       vecteur P1,N1,Q1,Vnum(2),Vden(1);
7115       polynome2poly1(P,1,P1);
7116       polynome2poly1(qmodp,1,Q1);
7117       polynome2poly1(nmodp,1,N1);
7118       gen a=P1.front(),b=P1[1],c=P1.back();
7119       gen q1,q2,n1,n2,aq2bq1;
7120       if (Q1.size()==2){
7121 	q1=Q1.front(); q2=Q1.back();
7122       }
7123       else
7124 	q2=Q1.front();
7125       aq2bq1=a*q2-b*q1;
7126       if (N1.size()==2){
7127 	n1=N1.front(); n2=N1.back();
7128       }
7129       else
7130 	n2=N1.front();
7131       Vnum[0]=(-q1*n2+q2*n1)*a;
7132       Vnum[1]=n2*aq2bq1+q1*n1*c;
7133       Vden[0]=q2*aq2bq1+c*q1*q1;
7134       polynome vnum(dim),vden(dim);
7135       poly12polynome(Vnum,1,vnum,dim);
7136       poly12polynome(Vden,1,vden,dim);
7137       simplify(qmodpden,nmodpden);
7138       simplify(vnum,vden);
7139       pfdecomp.push_back(pf<gen>(vnum*qmodpden,vden*nmodpden*P,P,1));
7140     }
7141   }
7142 
7143   // Input a,b,c,u,v,d such that a*u+b*v=d,
7144   // Output u,v,C such that a*u+b*v=c*C
egcdtoabcuv(const tensor<gen> & a,const tensor<gen> & b,const tensor<gen> & c,tensor<gen> & u,tensor<gen> & v,tensor<gen> & d,tensor<gen> & C)7145   void egcdtoabcuv(const tensor<gen> & a,const tensor<gen> &b, const tensor<gen> &c, tensor<gen> &u,tensor<gen> &v, tensor<gen> & d, tensor<gen> & C){
7146     if (Tis_constant(c)){
7147       C=d;
7148       u *= c.coord.front().value;
7149       v *= c.coord.front().value;
7150       return;
7151     }
7152     tensor<gen> d0(Tfirstcoeff(d));
7153     int m=c.lexsorted_degree();
7154     int n=d.lexsorted_degree();
7155     assert(m>=n); // degree of c must be greater than degree of d
7156     C=Tpow(d0,m-n+1);
7157     tensor<gen> coverd(a.dim),temp(a.dim);
7158     (c*C).TDivRem1(d,coverd,temp);
7159     assert(temp.coord.empty()); // division of c by d must be exact
7160     // now multiply a*u+b*v=d by coverd -> a*u*coverd+b*v*coverd=c*d0pow
7161     u *= coverd; // u=u*coverd;
7162     v *= coverd; // v=v*coverd;
7163     m=u.lexsorted_degree();
7164     n=b.lexsorted_degree();
7165     if (m<n)
7166       return;
7167     // then reduces the degree of u, a*u+b*v=c*C
7168     d0=Tpow(Tfirstcoeff(b),m-n+1);
7169     C *= d0; // C=C*d0;
7170     // now a*u*d0+b*v*d0=c*C
7171     (u*d0).TDivRem1(b,temp,u); // replace u*d0 -> temp*b+u
7172     // a*b + b*(a*temp+v*d0) = c*C
7173     v=a*temp+v*d0;
7174     return ;
7175   }
7176 
7177   // Bézout identity
7178   // given p and q, find u and v s.t. u*p+v*q=d where d=gcd(p,q) using PSR algo
7179   // Iterative algorithm to find u and d, then q=(d-u*p)/v
egcdpsr(const polynome & p1,const polynome & p2,polynome & u,polynome & v,polynome & d)7180   void egcdpsr(const polynome &p1, const polynome & p2, polynome & u,polynome & v,polynome & d){
7181     assert(p1.dim==p2.dim);
7182     // set auxiliary polynomials g and h to 1
7183     tensor<gen> g(gen(1),p1.dim);
7184     tensor<gen> h(g);
7185     tensor<gen> a(p1.dim),b(p1.dim),q(p1.dim),r(p1.dim);
7186     const tensor<gen> cp1=Tlgcd(p1);
7187     const tensor<gen> cp2=Tlgcd(p2);
7188     bool genswapped=false;
7189     if (p1.lexsorted_degree()<p2.lexsorted_degree())
7190       genswapped=true;
7191     // initializes a and b to p1, p2
7192     const tensor<gen> pp1=Tis_one(cp1)?p1:p1/cp1;
7193     const tensor<gen> pp2=Tis_one(cp2)?p2:p2/cp2;
7194     if (genswapped){
7195       a=pp2;
7196       b=pp1;
7197     }
7198     else {
7199       a=pp1;
7200       b=pp2;
7201     }
7202     // initializes ua to 1 and ub to 0, the coeff of u in ua*a+va*b=a
7203     tensor<gen> ua(gen(1),p1.dim), ub(p1.dim),ur(p1.dim);
7204     tensor<gen> b0pow(p1.dim);
7205     // loop: ddeg <- deg(a)-deg(b),
7206     // genDivRem: b0^(ddeg+1)*a = bq+r
7207     // hence ur <- ua*b0^(ddeg+1)-q*ub verifies
7208     // ur*a+vr*b=r
7209     // a <- b, b <- r/(g*h^ddeg), ua <- ub and ub<- ur/(g*h^ddeg)
7210     // g <- b0, h <- b0^(m-n) * h / h^ddeg
7211     for (;;){
7212       int n=b.lexsorted_degree();
7213       int m=a.lexsorted_degree();
7214       if (!n){ // b is cst !=0 hence is the gcd, ub is valid
7215 	break;
7216       }
7217       int ddeg=m-n;
7218       const tensor<gen> b0=Tfirstcoeff(b);
7219       // b0pow=genpow(b0,ddeg+1);
7220       // (a*b0pow).genDivRem1(b,q,r); // division works always
7221       a.TPseudoDivRem(b,q,r,b0pow);
7222       // if r is 0 then b is the gcd and ub the coeff
7223       if (r.coord.empty())
7224 	break;
7225       // COUT << ua*b0pow << '\n' << q*ub << '\n' ;
7226       (ua*b0pow).TSub(q*ub,ur); // ur=ua*b0pow-q*ub;
7227       // COUT << ur << '\n';
7228       swap(a,b); // a=b
7229       const tensor<gen> temp=Tpow(h,ddeg);
7230       // now divides r by g*h^(m-n), result is the new b
7231       r.TDivRem1(g*temp,b,q); // q is not used anymore
7232       swap(ua,ub); // ua=ub
7233       ur.TDivRem1(g*temp,ub,q);
7234       // COUT << (b-ub*p1) << "/" << p2 << '\n';
7235       // new g=b0 and new h=b0^(m-n)*h/temp
7236       if (ddeg==1) // the normal case, remainder deg. decreases by 1 each time
7237 	h=b0;
7238       else // not sure if it's better to keep temp or divide by h^(m-n+1)
7239 	(Tpow(b0,ddeg)*h).TDivRem1(temp,h,q);
7240       g=b0;
7241     }
7242     // ub is valid and b is the gcd, vb=(b-ub*p1)/p2 if not Tswapped
7243     // vb is stored in ua
7244     // COUT << ub << '\n';
7245     if (genswapped){
7246       (b-ub*pp2).TDivRem1(pp1,ua,r);
7247       ua *= cp2; // ua=ua*cp2;
7248       ub *= cp1; // ub=ub*cp1;
7249       b *= cp1; b *= cp2; // b=b*cp1*cp2;
7250     }
7251     else {
7252       (b-ub*pp1).TDivRem1(pp2,ua,r);
7253       ua *= cp1; // ua=ua*cp1;
7254       ub *= cp2; // ub=ub*cp2;
7255       b *= cp1; b *= cp2; // b=b*cp1*cp2;
7256     }
7257     // final simplifications
7258     q.coord.clear();
7259     Tlgcd(b,q); // q=Tlgcd(b);
7260     Tlgcd(ua,q);
7261     Tlgcd(ub,q);
7262     b.TDivRem1(q,d,r,true);  // d=b/Tlgcd
7263     if (genswapped){
7264       ub.TDivRem1(q,v,r,true); // v=ub/Tlgcd
7265       ua.TDivRem1(q,u,r,true); // u=ua/Tlgcd
7266     }
7267     else {
7268       ub.TDivRem1(q,u,r,true); // u=ub/Tlgcd
7269       ua.TDivRem1(q,v,r,true); // v=ua/Tlgcd
7270     }
7271   }
7272 
intreduce_pf(const pf<gen> & p_cst,vector<pf<gen>> & intdecomp,bool residue)7273   pf<gen> intreduce_pf(const pf<gen> & p_cst, vector< pf<gen> > & intdecomp ,bool residue){
7274     assert(p_cst.mult>0);
7275     if (p_cst.mult==1)
7276       return p_cst;
7277     pf<gen> p(p_cst);
7278     tensor<gen> fprime=p.fact.derivative();
7279     tensor<gen> d(fprime.dim),u(fprime.dim),v(fprime.dim),C(fprime.dim);
7280     tensor<gen> resnum(fprime.dim);
7281     gen resden(1),dengcd(1);
7282     egcdpsr(p.fact,fprime,u,v,d); // f*u+f'*v=d
7283     tensor<gen> usave(u),vsave(v);
7284     int initial_mult=p.mult-1;
7285     gen currentden=p.den/pow(p.fact,p.mult); // p.den.coord.front().value/pow(p.fact.coord.front().value,p.mult,context0);
7286     p.den=tensor<gen>(monomial<gen>(1,p.fact.dim));
7287     while (p.mult>1){
7288       egcdtoabcuv(p.fact,fprime,p.num,u,v,d,C);
7289       p.mult--;
7290       if (currentden.type==_POLY)
7291 	currentden=gen(p.mult)*C*(*currentden._POLYptr);
7292       else
7293 	currentden=gen(p.mult)*C*currentden;
7294       p.num=u*gen(p.mult)+v.derivative();
7295       if (!residue){ // resnum/resden + (-v*p.den)/currentden -> resnum/resden
7296 	dengcd=simplify3(resden,currentden);
7297 	if (currentden.type==_POLY)
7298 	  resnum=resnum*(*currentden._POLYptr);
7299 	else
7300 	  resnum=resnum*currentden;
7301 	if (resden.type==_POLY)
7302 	  resnum=resnum-(*resden._POLYptr)*v*p.den;
7303 	else
7304 	  resnum=resnum-resden*v*p.den;
7305 	resden=dengcd*resden*currentden;
7306 	currentden = dengcd*currentden; // restore currentden
7307 	p.den=p.den*p.fact;
7308       }
7309       // simplify from time to time
7310       if (p.mult%5 ==1){
7311 	gen gn=lgcd(p.num);
7312 	gen gn1=simplify3(gn,currentden);
7313 	if (gn1.type==_POLY)
7314 	  p.num = p.num / *gn1._POLYptr;
7315 	else
7316 	  p.num/=gn1;
7317       }
7318       if (p.mult==1)
7319 	break;
7320       u=usave;
7321       v=vsave;
7322     }
7323     if (!residue){
7324       p.den=resden.type==_POLY?(*resden._POLYptr)*p.den:resden*p.den;
7325       TsimplifybyTlgcd(resnum,p.den);
7326       intdecomp.push_back(pf<gen>(resnum,p.den,p.fact,initial_mult));
7327     }
7328     p.den=(currentden.type==_POLY)?(*currentden._POLYptr)*p.fact:currentden*p.fact;
7329     return pf<gen>(p);
7330   }
7331 
vector_of_polynome2vecteur(const vectpoly & v)7332   vecteur vector_of_polynome2vecteur(const vectpoly & v){
7333     vecteur res;
7334     vectpoly::const_iterator it=v.begin(),itend=v.end();
7335     res.reserve(itend-it);
7336     for (;it!=itend;++it)
7337       res.push_back(*it);
7338     return res;
7339   }
7340 
sturm_seq(const polynome & p,polynome & cont)7341   vecteur sturm_seq(const polynome & p,polynome & cont){
7342     vectpoly v;
7343     Tsturm_seq<gen>(p,cont,v);
7344     return vector_of_polynome2vecteur(v);
7345   }
7346 
7347   /* FAST PEVAL */
7348   /*
7349   // accumulate partial evaluation in polynomial (it,itend)
7350   // cur_index and nvar indicate the number of first identical eval.variables
7351   // vsize is the total number of eval.variables
7352   polynome peval(vector< monomial<gen> >::const_iterator & it,const vector< monomial<gen> >::const_iterator & itend,const vector< vecteur > & power_of_xi,index_t & cur_index,int nvar,int vsize,int var0){
7353     polynome res(var0);
7354     for (;;){
7355       if (it==itend)
7356 	return res;
7357       const index_t & it_t=it->index.iref();
7358       index_t::const_iterator it_tt=it_t.begin();
7359       index_t::const_iterator it_ttend=it_tt+nvar,cur_it=cur_index.begin();
7360       for (;it_tt!=it_ttend;++cur_it,++it_tt){
7361 	if (*it_tt!=*cur_it)
7362 	  return res;
7363       }
7364       // same index beginning
7365       if (nvar==vsize){
7366 	res.coord.push_back(monomial<gen>(it->value,index_t(it_t.begin()+vsize,it_t.end())));
7367 	++it;
7368 	if (debug_infolevel)
7369 	  CERR << "// " << itend-it << " monomials remain " << CLOCK() << '\n';
7370       }
7371       else { // go one level deeper
7372 	cur_index.push_back(*(it->index.begin()+nvar));
7373 	const gen & g=power_of_xi[nvar][cur_index.back()];
7374 	if (debug_infolevel)
7375 	  CERR << "// Enter level " << nvar+1 << " " << CLOCK() << '\n';
7376 	if (g.type==_POLY)
7377 	  res=res+(*g._POLYptr)*peval(it,itend,power_of_xi,cur_index,nvar+1,vsize,var0);
7378 	else
7379 	  res=res+g*peval(it,itend,power_of_xi,cur_index,nvar+1,vsize,var0);
7380 	cur_index.pop_back();
7381 	if (debug_infolevel)
7382 	  CERR << "// Back to level " << nvar << " " << CLOCK() << '\n';
7383       }
7384     }
7385   }
7386 
7387   gen peval(const polynome & p,const vecteur & v){
7388     int pdim=p.dim,vsize=v.size(),var0=pdim-vsize;
7389     if (var0<0)
7390       setsizeerr(gettext("Too much substitution variables"));
7391     polynome res(var0);
7392     if (p.coord.empty())
7393       return res;
7394     vecteur vnum,vden;
7395     gen vn,vd;
7396     vnum.reserve(vsize);
7397     vden.reserve(vsize);
7398     for (int i=0;i<vsize;++i){
7399       fxnd(v[i],vn,vd);
7400       vnum.push_back(vn);
7401       vden.push_back(vd);
7402     }
7403     vector< vecteur > power_of_xi;
7404     power_of_xi.reserve(pdim);
7405     index_t pdeg(p.degree());
7406     index_t deg(pdeg.begin(),pdeg.begin()+vsize);
7407     // compute thet table of powers
7408     gen global_deno(plus_one);
7409     for (int i=0;i<vsize;++i){
7410       if (debug_infolevel)
7411 	CERR << "// Computing powers of " << i << "th var " << CLOCK() << '\n';
7412       // compute powers of ith component num and deno
7413       vecteur va(1,plus_one),vb(1,plus_one);
7414       gen vn(vnum[i]),vd(vden[i]),vnpow(plus_one),vdpow(plus_one);
7415       int degi=deg[i];
7416       for (int j=1;j<=degi;++j){
7417 	vnpow=vnpow*vn;
7418 	va.push_back(vnpow);
7419 	vdpow=vdpow*vd;
7420 	vb.push_back(vdpow);
7421       }
7422       // multiply in reverse order for the denominators
7423       for (int j=0;j<=degi;++j)
7424 	va[j]=va[j]*vb[degi-j];
7425       global_deno=global_deno*vb.back();
7426       power_of_xi.push_back(va);
7427     }
7428     // we are now ready to evaluate the polynomial
7429     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
7430     index_t cur_index;
7431     return fraction(peval(it,itend,power_of_xi,cur_index,0,vsize,var0),global_deno);
7432   }
7433   */
7434 
7435   // a*b+c*d
foisplus(const polynome & a,const polynome & b,const polynome & c,const polynome & d)7436   gen foisplus(const polynome & a,const polynome & b,const polynome & c,const polynome & d){
7437     if (debug_infolevel >= 20-a.dim)
7438       CERR << "foisplus begin " << CLOCK() << '\n';
7439 #ifndef NO_TEMPLATE_MULTGCD
7440     index_t da=a.degree(),db=b.degree(),dc=c.degree(),dd=d.degree(),de(a.dim);
7441     double ans=1;
7442     for (int i=0;i<a.dim;++i){
7443       de[i]=giacmax(da[i]+db[i]+1,dc[i]+dd[i]+1);
7444       ans = ans*unsigned(de[i]);
7445       if (ans/RAND_MAX>RAND_MAX)
7446 	break;
7447     }
7448     if (ans<=RAND_MAX){
7449       ref_polynome * res = new ref_polynome(a.dim);
7450       vector< T_unsigned<gen,unsigned> > pa,pb,p,pc,pd;
7451       convert<gen,unsigned>(a,de,pa);
7452       convert<gen,unsigned>(b,de,pb);
7453       smallmult<gen,unsigned>(pa,pb,p,0,100);
7454       convert<gen,unsigned>(c,de,pc);
7455       convert<gen,unsigned>(d,de,pd);
7456       smallmult<gen,unsigned>(pc,pd,pa,0,100);
7457       smalladd<gen,unsigned>(p,pa,pb);
7458       convert<gen,unsigned>(pb,de,res->t);
7459       if (debug_infolevel >= 20-a.dim)
7460 	CERR << "foisplus end " << CLOCK() << '\n';
7461       // CERR << res->t-(a*b+c*d) << '\n';
7462       return res;
7463     }
7464     if (ans/RAND_MAX<RAND_MAX){
7465       ref_polynome * res = new ref_polynome(a.dim);
7466       vector< T_unsigned<gen,ulonglong> > pa,pb,p,pc,pd;
7467       convert<gen,ulonglong>(a,de,pa);
7468       convert<gen,ulonglong>(b,de,pb);
7469       smallmult<gen,ulonglong>(pa,pb,p,0,100);
7470       convert<gen,ulonglong>(c,de,pc);
7471       convert<gen,ulonglong>(d,de,pd);
7472       smallmult<gen,ulonglong>(pc,pd,pa,0,100);
7473       smalladd<gen,ulonglong>(p,pa,pb);
7474       convert<gen,ulonglong>(pb,de,res->t);
7475       // CERR << res->t << '\n' << (a*b+c*d) << '\n';
7476       return res;
7477     }
7478 #endif
7479     return a*b+c*d;
7480   }
7481 
foisplus(const gen & a,const gen & b,const gen & c,const gen & d)7482   gen foisplus(const gen & a,const gen & b,const gen & c,const gen & d){
7483     if (a.type==_POLY && b.type<_POLY  &&c.type==_POLY && d.type<_POLY){
7484       polynome res(a._POLYptr->dim);
7485       if (b==1){
7486 	if (d==1)
7487 	  a._POLYptr->TAdd(*c._POLYptr,res);
7488 	else {
7489 	  if (0 && c.ref_count()==1){
7490 	    *c._POLYptr *= d;
7491 	    a._POLYptr->TAdd(*c._POLYptr,res);
7492 	  } else {
7493 	    polynome cd(*c._POLYptr);
7494 	    cd *= d;
7495 	    a._POLYptr->TAdd(cd,res);
7496 	  }
7497 	}
7498 	return res;
7499       }
7500       if (0 && a.ref_count()==1){
7501 	*a._POLYptr *= b;
7502 	return foisplus(a,1,c,d);
7503       }
7504       polynome ab(*a._POLYptr);
7505       ab *= b;
7506       if (d==1)
7507 	ab.TAdd(*c._POLYptr,res);
7508       else {
7509 	polynome cd(*c._POLYptr);
7510 	cd *= d;
7511 	ab.TAdd(cd,res);
7512       }
7513       return res;
7514     }
7515     return a*b+c*d;
7516   }
7517 
pevaladd(const gen & aa,const gen & bb)7518   static gen pevaladd(const gen & aa,const gen & bb){
7519     if (debug_infolevel>40)
7520       CERR << "pevaladd begin " << CLOCK() << '\n';
7521     gen res=aa+bb;
7522     if (debug_infolevel>40)
7523       CERR << "pevaladd end " << CLOCK() << '\n';
7524     return res;
7525   }
7526 
pevalmul(const gen & aa,const gen & bb,const gen & m)7527   static gen pevalmul(const gen & aa,const gen & bb,const gen & m){
7528     if (debug_infolevel>40)
7529       CERR << "pevalmul begin " << CLOCK() << '\n';
7530     gen res;
7531     if (!is_zero(m))
7532       res=smod(aa,m)*bb;
7533     else
7534       res=aa*bb;
7535     /*
7536     if ( (aa.type!=_FRAC) || (bb.type!=_FRAC) )
7537       return aa*bb;
7538     const Tfraction<gen> & a(*aa._FRACptr);
7539     const Tfraction<gen> & b(*bb._FRACptr);
7540     gen res(Tfraction<gen>(a.num*b.num,a.den*b.den));
7541     */
7542     if (debug_infolevel>40)
7543       CERR << "pevalmul end " << CLOCK() << '\n';
7544     return res;
7545   }
7546 
7547   // Horner like evaluation
7548   // m != 0 for modular evaluation
peval(vector<monomial<gen>>::const_iterator & it,const vector<monomial<gen>>::const_iterator & itend,const vecteur & nums,const vecteur & dens,const index_t & deg,index_t & cur_index,int nvar,int vsize,int var0,const gen & m)7549   static gen peval(vector< monomial<gen> >::const_iterator & it,const vector< monomial<gen> >::const_iterator & itend,const vecteur & nums,const vecteur & dens,const index_t & deg,index_t & cur_index,int nvar,int vsize,int var0,const gen & m){
7550     if (it==itend)
7551       return zero;
7552     if (nvar==vsize){
7553       polynome res(var0);
7554       for (;;){
7555 	if (it==itend)
7556 	  return res;
7557 	index_t::const_iterator it_tt=it->index.begin();
7558 	index_t::const_iterator it_ttend=it_tt+nvar,cur_it=cur_index.begin();
7559 	for (;it_tt!=it_ttend;++cur_it,++it_tt){
7560 	  if (*it_tt!=*cur_it){
7561 	    return res;
7562 	  }
7563 	}
7564 	// same main variables powers, accumulate constants
7565 	res.coord.push_back(monomial<gen>(it->value,index_t(it->index.begin()+vsize,it->index.end())));
7566 	++it;
7567       if (debug_infolevel>40)
7568 	CERR << "// " << itend-it << " monomials remain " << CLOCK() << '\n';
7569       }
7570     }
7571     // we are not at the deepest level
7572     gen res,tmp1,tmp2;
7573     int prev_power=0,cur_power=deg[nvar];
7574     const gen & gn=nums[nvar];
7575     const gen & gd=dens[nvar];
7576     gen cur_gd(plus_one);
7577     if (is_zero(gn)){ // if gn=0 we just discard monomials
7578       for (;;){
7579 	if (it==itend)
7580 	  return zero;
7581 	index_t::const_iterator it_tt=it->index.begin();
7582 	index_t::const_iterator it_ttend=it_tt+nvar,cur_it=cur_index.begin();
7583 	for (;it_tt!=it_ttend;++cur_it,++it_tt){
7584 	  if (*it_tt!=*cur_it)
7585 	    return zero;
7586 	}
7587 	if (!*it_tt) // break at first monomial with power = 0 at this index
7588 	  break;
7589 	++it;
7590       }
7591       cur_index.push_back(0);
7592       gen res(pow(gd,prev_power));
7593       if (!is_zero(m))
7594 	res=smod(res,m);
7595       res=res*peval(it,itend,nums,dens,deg,cur_index,nvar+1,vsize,var0,m);
7596       cur_index.pop_back();
7597       return res;
7598     } // end gn==0
7599     for (;;){
7600       prev_power=cur_power;
7601       if (it==itend){
7602 	if (!prev_power)
7603 	  return res;
7604 	else
7605 	  return pevalmul(pow(gn,prev_power),res,m);
7606 	// return pow(gn,prev_power)*res;
7607       }
7608       cur_power=*(it->index.begin()+nvar);
7609       // same powers for the beginning indices? (always true the first time)
7610       index_t::const_iterator it_tt=it->index.begin();
7611       index_t::const_iterator it_ttend=it_tt+nvar,cur_it=cur_index.begin();
7612       for (;it_tt!=it_ttend;++cur_it,++it_tt){
7613 	if (*it_tt!=*cur_it)
7614 	  return pevalmul(pow(gn,prev_power),res,m);
7615 	// return pow(gn,prev_power)*res;
7616       }
7617       // Yes: go one level deeper
7618       tmp1=pevalmul(pow(gn,prev_power-cur_power),res,m);
7619       res=zero;
7620       cur_index.push_back(cur_power);
7621       if (debug_infolevel>40)
7622 	CERR << "// Enter level " << nvar+1 << " " << CLOCK() << " ^ " << prev_power-cur_power << '\n';
7623       tmp2=peval(it,itend,nums,dens,deg,cur_index,nvar+1,vsize,var0,m);
7624       cur_index.pop_back();
7625       if (debug_infolevel>40)
7626 	CERR << "// Back to level " << nvar << " " << CLOCK() << '\n';
7627       cur_gd=cur_gd*pow(gd,prev_power-cur_power);
7628       if (!is_zero(m))
7629 	cur_gd=smod(cur_gd,m);
7630       // res=pevalmul(pow(gn,prev_power-cur_power),res)+cur_gd*peval(it,itend,nums,dens,deg,cur_index,nvar+1,vsize,var0);
7631       res=pevaladd(tmp1,cur_gd*tmp2);
7632       if (!is_zero(m))
7633 	res=smod(res,m);
7634       tmp1=zero;
7635       tmp2=zero;
7636     }
7637   }
7638 
smallmult(const std::vector<int_unsigned> & v1,const std::vector<int_unsigned> & v2,std::vector<int_unsigned> & v,int reduce,int possible_size=100)7639   static void smallmult(const std::vector< int_unsigned > & v1,const std::vector< int_unsigned > & v2,std::vector< int_unsigned > & v,int reduce,int possible_size=100){
7640 #ifdef HASH_MAP_NAMESPACE
7641     typedef HASH_MAP_NAMESPACE::hash_map<unsigned,int> hash_prod ;
7642     hash_prod produit(possible_size);
7643     // COUT << "hash " << CLOCK() << '\n';
7644 #else
7645     typedef std::map<unsigned,int> hash_prod;
7646     hash_prod produit;
7647     // COUT << "small map" << '\n';
7648 #endif
7649     hash_prod::iterator prod_it,prod_itend;
7650     std::vector< int_unsigned >::const_iterator it1=v1.begin(),it1end=v1.end(),it2beg=v2.begin(),it2,it2end=v2.end();
7651     // FIXME if reduce is small use int for g1,g instead of longlong
7652     longlong g1,g;
7653     unsigned u1,u;
7654     for (;it1!=it1end;++it1){
7655       g1=it1->g;
7656       u1=it1->u;
7657       for (it2=it2beg;it2!=it2end;++it2){
7658 	u=u1+it2->u;
7659 	g=g1*it2->g ; // moved % reduce so that 1 % is done instead of 2
7660 	prod_it=produit.find(u);
7661 	if (prod_it==produit.end())
7662 	  produit[u]=g % reduce;
7663 	else {
7664 	  int & s=prod_it->second;
7665 	  g += s;
7666 	  s = g % reduce;
7667 	}
7668       }
7669     }
7670     int_unsigned gu;
7671     prod_it=produit.begin(),prod_itend=produit.end();
7672     v.clear();
7673     v.reserve(produit.size());
7674     for (;prod_it!=prod_itend;++prod_it){
7675       if (!is_zero(gu.g=prod_it->second)){
7676 	gu.u=prod_it->first;
7677 	v.push_back(gu);
7678       }
7679     }
7680     // COUT << "smallmult end " << CLOCK() << '\n';
7681     sort(v.begin(),v.end());
7682   }
7683 
smallmult(int x,std::vector<int_unsigned> & v,int m)7684   static void smallmult(int x,std::vector<int_unsigned> & v,int m){
7685     if (!x){
7686       v.clear();
7687       return;
7688     }
7689     std::vector<int_unsigned>::iterator it=v.begin(),itend=v.end();
7690     for (;it!=itend;++it){
7691       it->g *= x;
7692       it->g %= m;
7693     }
7694   }
7695 
smalladd(const std::vector<int_unsigned> & v1,const std::vector<int_unsigned> & v2,int m,std::vector<int_unsigned> & v)7696   static void smalladd(const std::vector< int_unsigned > & v1,const std::vector< int_unsigned > & v2,int m,std::vector< int_unsigned > & v){
7697     std::vector< int_unsigned >::const_iterator it1=v1.begin(),it1end=v1.end(),it2=v2.begin(),it2end=v2.end();
7698     int g;
7699     v.clear();
7700     v.reserve((it1end-it1)+(it2end-it2)); // worst case
7701     for (;it1!=it1end && it2!=it2end;){
7702       if (it1->u==it2->u){
7703 	g=(it1->g+it2->g)%m;
7704 	if (g)
7705 	  v.push_back(int_unsigned(g,it1->u));
7706 	++it1;
7707 	++it2;
7708       }
7709       else {
7710 	if (it1->u>it2->u){
7711 	  v.push_back(*it1);
7712 	  ++it1;
7713 	}
7714 	else {
7715 	  v.push_back(*it2);
7716 	  ++it2;
7717 	}
7718       }
7719     }
7720     for (;it1!=it1end;++it1)
7721       v.push_back(*it1);
7722     for (;it2!=it2end;++it2)
7723       v.push_back(*it2);
7724   }
7725 
7726   // Poly evaluation of p at x modulo m, d is the degree in int_unsigned.u
peval(const vector<int_unsigned> & p,int d,int x,int m,vector<int_unsigned> & res)7727   static void peval(const vector<int_unsigned> & p,int d,int x,int m,vector<int_unsigned> & res){
7728     res.clear();
7729     vector<int_unsigned> tmp1,tmp2;
7730     if (p.empty())
7731       return;
7732     // CERR << p << '\n';
7733     vector<int_unsigned>::const_iterator it=p.begin(),itend=p.end();
7734     int deg=d*(it->u / d),ddeg;
7735     for (;deg>=0;deg -=d ){ // Horner like
7736       // CERR << res << '\n';
7737       smallmult(x,res,m);
7738       // CERR << res << '\n';
7739       tmp2.clear();
7740       // Find next coeff
7741       for (;it!=itend;++it){
7742 	ddeg=it->u-deg;
7743 	if (ddeg<0)
7744 	  break;
7745 	tmp2.push_back(int_unsigned(it->g,ddeg));
7746       }
7747       // CERR << tmp2 << '\n';
7748       tmp1=res;
7749       smalladd(tmp1,tmp2,m,res);
7750       // CERR << res << '\n';
7751     }
7752   }
7753 
peval(const polynome & p,const gen & x0,int m,polynome & g,vector<int_unsigned> * P)7754   static bool peval(const polynome & p,const gen & x0,int m,polynome & g,vector<int_unsigned> * P){
7755     gen x1=smod(x0,m);
7756     if (x1.type!=_INT_)
7757       return false;
7758     int x=x1.val;
7759     index_t d=p.degree();
7760     unsigned ans;
7761     if (!degree2unsigned(d,ans))
7762       return false;
7763     vector<int_unsigned> Q;
7764     if (!P)
7765       P=&Q;
7766     if (P->empty() && !convert(p,d,*P,m))
7767       return false;
7768     vector<int_unsigned> res;
7769     peval(*P,ans/d.front(),x,m,res);
7770     d.erase(d.begin());
7771     convert(res,d,g);
7772     return true;
7773   }
7774 
peval(const polynome & p,const vecteur & v,const gen & m,bool simplify_at_end,vector<int_unsigned> * pptr)7775   gen peval(const polynome & p,const vecteur & v,const gen & m,bool simplify_at_end,vector<int_unsigned> * pptr){
7776     int pdim=int(p.dim),vsize=int(v.size()),var0=pdim-vsize;
7777     if (v==vecteur(vsize)){ // fast evaluation at 0
7778       index_t i(pdim);
7779       i[vsize-1]=1;
7780       // i=(0,0,...,0,1)
7781       // find the last position in p where a monomial with index i
7782       // could be inserted, the remaining of p truncated is the answer
7783       vector< monomial<gen> >::const_iterator it,itend=p.coord.end();
7784       it=upper_bound(p.coord.begin(),itend,monomial<gen>(plus_one,i),p.m_is_strictly_greater);
7785       if ( (it!=itend) && it->index.iref()==i)
7786 	++it;
7787       polynome res(var0);
7788       res.coord.reserve(itend-it);
7789       for (;it!=itend;++it){
7790 	res.coord.push_back(monomial<gen>(it->value,index_t(it->index.begin()+vsize,it->index.end())));
7791       }
7792       return res;
7793     }
7794     if (vsize==1 && m.type==_INT_ && m.val>0 && m.val<46340){
7795       polynome res;
7796       if (peval(p,v.front(),m.val,res,pptr))
7797 	return res;
7798     }
7799     if (var0<0){
7800 #ifndef NO_STDEXCEPT
7801       setsizeerr(gettext("Too much substitution variables"));
7802 #else
7803       return gensizeerr(gettext("Too much substitution variables"));
7804 #endif
7805     }
7806     polynome res(var0);
7807     if (p.coord.empty())
7808       return res;
7809     vecteur vnum,vden;
7810     gen vn,vd;
7811     vnum.reserve(vsize);
7812     vden.reserve(vsize);
7813     if (simplify_at_end){
7814       for (int i=0;i<vsize;++i){
7815 	fxnd(v[i],vn,vd);
7816 	vnum.push_back(vn);
7817 	vden.push_back(vd);
7818       }
7819     }
7820     else {
7821       vnum=v;
7822       vden=vecteur(vsize,plus_one);
7823     }
7824     // we are now ready to evaluate the polynomial
7825     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
7826     index_t cur_index;
7827     index_t pdeg(p.degree());
7828     index_t deg(pdeg.begin(),pdeg.begin()+vsize);
7829     gen numer(peval(it,itend,vnum,vden,deg,cur_index,0,vsize,var0,m));
7830     if (!is_zero(m))
7831       numer=smod(numer,m);
7832     if (debug_infolevel>40){
7833       CERR << "// Peval end " << CLOCK();
7834       if (numer.type==_POLY)
7835 	CERR << " poly " << numer._POLYptr->coord.size();
7836       CERR << '\n';
7837     }
7838     if ( is_zero(numer))
7839       return numer;
7840     // compute thet table of powers
7841     gen global_deno(plus_one);
7842     for (int i=0;i<vsize;++i){
7843       global_deno=global_deno*pow(vden[i],deg[i]);
7844     }
7845     simplify(numer,global_deno);
7846     return fraction(numer,global_deno);
7847   }
7848 
7849 #if 0
7850   /* Not used anymore */
7851   static factorization vector2factorization(const vectpoly & v){
7852     vectpoly::const_iterator it=v.begin(),itend=v.end();
7853     factorization res;
7854     for (int i=1;it!=itend;++it){
7855       if (Tis_one<gen>(*it))
7856 	res.push_back(facteur<polynome>(*it,i));
7857     }
7858     return res;
7859   }
7860 #endif
7861 
7862 #ifndef NO_NAMESPACE_GIAC
7863 } // namespace giac
7864 #endif // ndef NO_NAMESPACE_GIAC
7865