1 /* -*- mode:C++ ; compile-command: "g++-3.4 -I.. -I../include -g -c threaded.cc -DHAVE_CONFIG_H -DIN_GIAC  -D_I386_" -*- */
2 #include "giacPCH.h"
3 /*  Copyright (C) 2000,2007 B. Parisse, Institut Fourier, 38402 St Martin d'Heres
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 using namespace std;
19 #include "threaded.h"
20 #include "sym2poly.h"
21 #include "gausspol.h"
22 #include "usual.h"
23 #include "monomial.h"
24 #include "modpoly.h"
25 #include "giacintl.h"
26 #include "input_parser.h"
27 #include "kdisplay.h"
28 #ifdef FXCG
29 extern "C" {
30 #include <system.h>
31 }
32 #endif
33 
34 #ifndef NO_NAMESPACE_GIAC
35 namespace giac {
36 #endif // ndef NO_NAMESPACE_GIAC
37 
38 #ifdef HAVE_GMPXX_H
invmod(const mpz_class & a,int reduce)39 mpz_class invmod(const mpz_class & a,int reduce){
40   mpz_class z=(a%reduce);
41   int tmp=z.get_si();
42   tmp=giac::invmod(tmp,reduce);
43   return tmp;
44 }
45 
smod(const mpz_class & a,int reduce)46 mpz_class smod(const mpz_class & a,int reduce){
47   mpz_class z=(a%reduce);
48   int tmp=z.get_si();
49   tmp=giac::smod(tmp,reduce);
50   return tmp;
51 }
52 #endif
53 
54   double heap_mult=20000;
_heap_mult(const gen & g0,GIAC_CONTEXT)55   gen _heap_mult(const gen & g0,GIAC_CONTEXT){
56     if ( g0.type==_STRNG && g0.subtype==-1) return  g0;
57     gen g=evalf_double(g0,1,contextptr);
58     if (g.type!=_DOUBLE_)
59       return heap_mult;
60     return heap_mult=g._DOUBLE_val;
61   }
62   static const char _heap_mult_s []="heap_mult";
63   static define_unary_function_eval (__heap_mult,&_heap_mult,_heap_mult_s);
64   define_unary_function_ptr5( at_heap_mult ,alias_at_heap_mult,&__heap_mult,0,true);
65 
_half_gcd(const gen & g,GIAC_CONTEXT)66   gen _half_gcd(const gen & g,GIAC_CONTEXT){
67     if ( g.type==_STRNG && g.subtype==-1) return  g;
68     if (g.type!=_INT_ || g.val<0)
69       return gensizeerr(contextptr);
70     if (g.val>0)
71       HGCD=g.val;
72     return HGCD;
73   }
74   static const char _half_gcd_s []="half_gcd";
75   static define_unary_function_eval (__half_gcd,&_half_gcd,_half_gcd_s);
76   define_unary_function_ptr5( at_half_gcd ,alias_at_half_gcd,&__half_gcd,0,true);
77 
_ntl_modgcd(const gen & g,GIAC_CONTEXT)78   gen _ntl_modgcd(const gen & g,GIAC_CONTEXT){
79     if ( g.type==_STRNG && g.subtype==-1) return  g;
80     if (g.type==_VECT)
81       return NTL_MODGCD;
82     if (g.type!=_INT_ || g.val<0)
83       return gensizeerr(contextptr);
84     if (g.val>0)
85       NTL_MODGCD=g.val;
86     return NTL_MODGCD;
87   }
88   static const char _ntl_modgcd_s []="ntl_modgcd";
89   static define_unary_function_eval (__ntl_modgcd,&_ntl_modgcd,_ntl_modgcd_s);
90   define_unary_function_ptr5( at_ntl_modgcd ,alias_at_ntl_modgcd,&__ntl_modgcd,0,true);
91 
_ntl_xgcd(const gen & g,GIAC_CONTEXT)92   gen _ntl_xgcd(const gen & g,GIAC_CONTEXT){
93     if ( g.type==_STRNG && g.subtype==-1) return  g;
94     if (g.type==_VECT)
95       return NTL_XGCD;
96     if (g.type!=_INT_ || g.val<0)
97       return gensizeerr(contextptr);
98     if (g.val>0)
99       NTL_XGCD=g.val;
100     return NTL_XGCD;
101   }
102   static const char _ntl_xgcd_s []="ntl_xgcd";
103   static define_unary_function_eval (__ntl_xgcd,&_ntl_xgcd,_ntl_xgcd_s);
104   define_unary_function_ptr5( at_ntl_xgcd ,alias_at_ntl_xgcd,&__ntl_xgcd,0,true);
105 
_ntl_resultant(const gen & g,GIAC_CONTEXT)106   gen _ntl_resultant(const gen & g,GIAC_CONTEXT){
107     if ( g.type==_STRNG && g.subtype==-1) return  g;
108     if (g.type==_VECT)
109       return NTL_RESULTANT;
110     if (g.type!=_INT_ || g.val<0)
111       return gensizeerr(contextptr);
112     if (g.val>0)
113       NTL_RESULTANT=g.val;
114     return NTL_RESULTANT;
115   }
116   static const char _ntl_resultant_s []="ntl_resultant";
117   static define_unary_function_eval (__ntl_resultant,&_ntl_resultant,_ntl_resultant_s);
118   define_unary_function_ptr5( at_ntl_resultant ,alias_at_ntl_resultant,&__ntl_resultant,0,true);
119 
_modresultant(const gen & g,GIAC_CONTEXT)120   gen _modresultant(const gen & g,GIAC_CONTEXT){
121     if ( g.type==_STRNG && g.subtype==-1) return  g;
122     if (g.type==_VECT)
123       return MODRESULTANT;
124     if (g.type!=_INT_ || g.val<0)
125       return gensizeerr(contextptr);
126     if (g.val>0)
127       MODRESULTANT=g.val;
128     return MODRESULTANT;
129   }
130   static const char _modresultant_s []="modresultant";
131   static define_unary_function_eval (__modresultant,&_modresultant,_modresultant_s);
132   define_unary_function_ptr5( at_modresultant ,alias_at_modresultant,&__modresultant,0,true);
133 
134   double modgcd_cachesize=6291456;
_modgcd_cachesize(const gen & g0,GIAC_CONTEXT)135   gen _modgcd_cachesize(const gen & g0,GIAC_CONTEXT){
136     if ( g0.type==_STRNG && g0.subtype==-1) return  g0;
137     gen g=evalf_double(g0,1,contextptr);
138     if (g.type!=_DOUBLE_)
139       return modgcd_cachesize;
140     return modgcd_cachesize=g._DOUBLE_val;
141   }
142   static const char _modgcd_cachesize_s []="modgcd_cachesize";
143   static define_unary_function_eval (__modgcd_cachesize,&_modgcd_cachesize,_modgcd_cachesize_s);
144   define_unary_function_ptr5( at_modgcd_cachesize ,alias_at_modgcd_cachesize,&__modgcd_cachesize,0,true);
145 
_debug_infolevel(const gen & g0,GIAC_CONTEXT)146   gen _debug_infolevel(const gen & g0,GIAC_CONTEXT){
147     if ( g0.type==_STRNG && g0.subtype==-1) return  g0;
148     gen g=evalf_double(g0,1,contextptr);
149     if (g.type!=_DOUBLE_)
150       return debug_infolevel;
151     return debug_infolevel=int(g._DOUBLE_val);
152   }
153   static const char _debug_infolevel_s []="debug_infolevel";
154   static define_unary_function_eval (__debug_infolevel,&_debug_infolevel,_debug_infolevel_s);
155   define_unary_function_ptr5( at_debug_infolevel ,alias_at_debug_infolevel,&__debug_infolevel,0,T_DIGITS);
156 
_step_infolevel(const gen & g0,GIAC_CONTEXT)157   gen _step_infolevel(const gen & g0,GIAC_CONTEXT){
158     if ( g0.type==_STRNG && g0.subtype==-1) return  g0;
159     gen g=evalf_double(g0,1,contextptr);
160     if (g.type!=_DOUBLE_)
161       return step_infolevel(contextptr);
162     return step_infolevel(contextptr)=int(g._DOUBLE_val);
163   }
164   static const char _step_infolevel_s []="step_infolevel";
165   static define_unary_function_eval (__step_infolevel,&_step_infolevel,_step_infolevel_s);
166   define_unary_function_ptr5( at_step_infolevel ,alias_at_step_infolevel,&__step_infolevel,0,true);
167 
operator %(const my_mpz & a,const my_mpz & b)168   my_mpz operator % (const my_mpz & a,const my_mpz & b){
169     my_mpz tmp;
170     mpz_fdiv_r(tmp.ptr,a.ptr,b.ptr);
171     return tmp;
172   }
173 
operator %=(my_mpz & a,const my_mpz & b)174   my_mpz operator %= (my_mpz & a,const my_mpz & b){
175     mpz_fdiv_r(a.ptr,a.ptr,b.ptr);
176     return a;
177   }
178 
operator +=(my_mpz & a,const my_mpz & b)179   my_mpz operator += (my_mpz & a,const my_mpz & b){
180     mpz_add(a.ptr,a.ptr,b.ptr);
181     return a;
182   }
183 
operator -=(my_mpz & a,const my_mpz & b)184   my_mpz operator -= (my_mpz & a,const my_mpz & b){
185     mpz_sub(a.ptr,a.ptr,b.ptr);
186     return a;
187   }
188 
operator +(const my_mpz & a,const my_mpz & b)189   my_mpz operator + (const my_mpz & a,const my_mpz & b){
190     my_mpz tmp;
191     mpz_add(tmp.ptr,a.ptr,b.ptr);
192     return tmp;
193   }
194 
operator -(const my_mpz & a,const my_mpz & b)195   my_mpz operator - (const my_mpz & a,const my_mpz & b){
196     my_mpz tmp;
197     mpz_sub(tmp.ptr,a.ptr,b.ptr);
198     return tmp;
199   }
200 
operator *(const my_mpz & a,const my_mpz & b)201   my_mpz operator * (const my_mpz & a,const my_mpz & b){
202     my_mpz tmp;
203     mpz_mul(tmp.ptr,a.ptr,b.ptr);
204     return tmp;
205   }
206 
operator /(const my_mpz & a,const my_mpz & b)207   my_mpz operator / (const my_mpz & a,const my_mpz & b){
208     my_mpz tmp;
209     mpz_fdiv_q(tmp.ptr,a.ptr,b.ptr);
210     return tmp;
211   }
212 
invmod(const my_mpz & a,int reduce)213   my_mpz invmod(const my_mpz & a,int reduce){
214     my_mpz z=(a%reduce);
215     int tmp=mpz_get_si(z.ptr);
216     tmp=invmod(tmp,reduce);
217     return tmp;
218   }
219 
smod(const my_mpz & a,int reduce)220   my_mpz smod(const my_mpz & a,int reduce){
221     my_mpz z=(a%reduce);
222     int tmp=mpz_get_si(z.ptr);
223     tmp=smod(tmp,reduce);
224     return tmp;
225   }
226 
227 
228 #ifdef KHICAS
wait_1ms(int ms)229   void wait_1ms(int ms){
230     os_wait_1ms(ms);
231   }
232 #else
233 #ifdef FXCG
wait_1ms(int ms)234   void wait_1ms(int ms){
235     OS_InnerWait_ms(ms);
236   }
237 #else
wait_1ms(int ms)238   void wait_1ms(int ms){
239 #ifdef NSPIRE
240     sleep(ms);
241 #else
242     usleep(ms*1000);
243 #endif
244   }
245 #endif
246 #endif
247 
background_callback(const gen & g,void * newcontextptr)248   void background_callback(const gen & g,void * newcontextptr){
249     if (g.type==_VECT && g._VECTptr->size()==2){
250       context * cptr=(context *)newcontextptr;
251       if (cptr){
252 #ifdef HAVE_LIBPTHREAD
253 	pthread_mutex_lock(cptr->globalptr->_mutex_eval_status_ptr);
254 	sto(g._VECTptr->back(),g._VECTptr->front(),cptr);
255 	pthread_mutex_unlock(cptr->globalptr->_mutex_eval_status_ptr);
256 #endif
257       }
258     }
259   }
260 
_background(const gen & g,GIAC_CONTEXT)261   gen _background(const gen & g,GIAC_CONTEXT){
262     if ( g.type==_STRNG && g.subtype==-1) return  g;
263 #ifdef HAVE_LIBPTHREAD
264     if (g.type!=_VECT || g._VECTptr->size()<2)
265       return gensizeerr(contextptr);
266     vecteur v(*g._VECTptr);
267     gen target=v[0];
268     gen toeval=v[1];
269     int s=v.size();
270     double maxsize=1e9; // in bytes
271     double maxtime=1e9; // in microseconds
272     int level=eval_level(contextptr);
273     if (s>2){
274       gen tmp=evalf_double(v[2],level,contextptr);
275       if (tmp.type!=_DOUBLE_)
276 	return gentypeerr(contextptr);
277       maxsize=tmp._DOUBLE_val;
278     }
279     if (s>3){
280       gen tmp=evalf_double(v[3],level,contextptr);
281       if (tmp.type!=_DOUBLE_)
282 	return gentypeerr(contextptr);
283       maxtime=tmp._DOUBLE_val;
284     }
285     if (s>4 && v[4].type==_INT_)
286       level=v[4].val;
287     gen tmp;
288     context * newcontextptr=clone_context(contextptr);
289     newcontextptr->parent=contextptr;
290     tmp=gen(newcontextptr,_THREAD_POINTER);
291     sto(tmp,target,contextptr);
292     if (!make_thread(makevecteur(symbolic(at_quote,target),toeval),level,background_callback,(void *)newcontextptr,newcontextptr)){
293       sto(undef,target,contextptr);
294       return gensizeerr(gettext("Unable to make thread"));
295     }
296     return tmp;
297 #else
298     return undef;
299 #endif
300   }
301   static const char _background_s []="background";
302   static define_unary_function_eval_quoted (__background,&_background,_background_s);
303   define_unary_function_ptr5( at_background ,alias_at_background,&__background,_QUOTE_ARGUMENTS,true);
304 
305   // check if var is a power of 2
find_shift(const hashgcd_U & var)306   static int find_shift(const hashgcd_U & var){
307     hashgcd_U u(var);
308     int shift=-1;
309     for (;u;u = u>> 1){
310       ++shift;
311     }
312     return (int(var) == (1<<shift) )?shift:-1;
313   }
314 
find_shift(const std::vector<hashgcd_U> & vars,index_t & shift)315   static bool find_shift(const std::vector<hashgcd_U> & vars,index_t & shift){
316     shift.clear();
317     std::vector<hashgcd_U>::const_iterator it=vars.begin(),itend=vars.end();
318     shift.reserve(itend-it);
319     for (;it!=itend;++it){
320       shift.push_back(find_shift(*it));
321       if (shift.back()==-1)
322 	return false;
323     }
324     return true;
325   }
326 
gcdsmallmodpoly(const vector<int> & a,const vector<int> & b,const vector<int> * pminptr,int modulo,vector<int> & d)327   static bool gcdsmallmodpoly(const vector<int> & a,const vector<int> & b,const vector<int> * pminptr,int modulo,vector<int> & d){
328     gcdsmallmodpoly(a,b,modulo,d);
329     return true;
330   }
331 
DivRem(const vector<int> & a,const vector<int> & b,const vector<int> * pminptr,int modulo,vector<int> & q,vector<int> & r)332   static bool DivRem(const vector<int> & a,const vector<int> & b,const vector<int> * pminptr,int modulo,vector<int> & q,vector<int> & r){
333     DivRem(a,b,modulo,q,r);
334     return true;
335   }
336 
337   static bool divrem_(vector< vector<int> > & a,vector< vector<int> > & b,const vector<int> & pmin, int modulo, vector< vector<int> > * qptr,bool set_q_orig_b,vector<int> & b0,vector<int> & b0inv,vector<int> & tmp,vector<int> & tmp1,vector<int> & tmp2,vector<int> & tmp3,vector<int> & tmp4,vector<int> & tmp5);
338 
DivRem(const vector<vector<int>> & a,const vector<vector<int>> & b,const vector<int> * pminptr,int modulo,vector<vector<int>> & q,vector<vector<int>> & r)339   bool DivRem(const vector< vector<int> > & a,const vector< vector<int> > & b,const vector<int> * pminptr,int modulo,vector< vector<int> > & q,vector< vector<int> > & r){
340     r=a;
341     vector< vector<int> > b0(b);
342     vector<int> B0,B0inv,tmp,tmp1,tmp2,tmp3,tmp4,tmp5;
343     return divrem_(r,b0,*pminptr,modulo,&q,true,B0,B0inv,tmp,tmp1,tmp2,tmp3,tmp4,tmp5);
344   }
345 
346   static bool gcdsmallmodpoly_ext(const vector< vector<int> > & p,const vector< vector<int> > & q,const vector<int> & pmin,int modulo,vector< vector<int> > & d);
347 
gcdsmallmodpoly(const vector<vector<int>> & a,const vector<vector<int>> & b,const vector<int> * pminptr,int modulo,vector<vector<int>> & d)348   static bool gcdsmallmodpoly(const vector< vector<int> > & a,const vector< vector<int> > & b,const vector<int> * pminptr,int modulo,vector< vector<int> > & d){
349     return gcdsmallmodpoly_ext(a,b,*pminptr,modulo,d);
350   }
351 
is_zero(const vector<int> & v)352   bool is_zero(const vector<int> & v){
353     vector<int>::const_iterator it=v.begin(),itend=v.end();
354     for (;it!=itend;++it){
355       if (*it)
356 	return false;
357     }
358     return true;
359   }
360 
make_unit(int)361   inline int make_unit(int ){
362     return 1;
363   }
364 
make_unit(const vector<int>)365   inline vector<int> make_unit(const vector<int>){
366     vector<int> v(1,1);
367     return v;
368   }
369 
370   // extract modular content of p wrt to the last variable
371   // returns 0 on failure, 1 on success with trivial content and res not compute
372   // 2 on success with non trivial content and res computed
373   template<class T>
pp_mod_last(const vector<T_unsigned<T,hashgcd_U>> & p,const vector<int> * pminptr,int modulo,hashgcd_U var,hashgcd_U var2,vector<T> & pcontxn,vector<T_unsigned<T,hashgcd_U>> & res)374   static int pp_mod_last(const vector< T_unsigned<T,hashgcd_U> > & p,const vector<int> * pminptr,int modulo,hashgcd_U var,hashgcd_U var2,vector<T> & pcontxn,vector< T_unsigned<T,hashgcd_U> > & res){
375     typename vector< T_unsigned<T,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
376     pcontxn.clear();
377     if (it==itend){
378       res.clear();
379       return 2;
380     }
381     hashgcd_U u=(p.front().u/var)*var,curu,newu=0;
382     if (u==p.front().u){
383       pcontxn.push_back(make_unit(p.front().g));
384       return 1;
385     }
386     vector<T> current,tmp,reste;
387     // for degree >= 256 it will reallocate
388     pcontxn.reserve(256); current.reserve(256); tmp.reserve(256); reste.reserve(256);
389     for (;it!=itend;){
390       current.clear();
391       current.push_back(it->g);
392       curu=it->u;
393       ++it;
394       for (;it!=itend;++it){
395 	newu=it->u;
396 	if ( newu < u ){
397 	  break;
398 	}
399 	if (curu>newu+var2)
400 	  current.insert(current.end(),(curu-newu)/var2-1,T(0));
401 	current.push_back(it->g);
402 	curu=newu;
403       }
404       if (curu>u)
405 	current.insert(current.end(),(curu-u)/var2,T(0));
406 #ifdef TIMEOUT
407       control_c();
408 #endif
409       if (ctrl_c || interrupted || !gcdsmallmodpoly(pcontxn,current,pminptr,modulo,tmp))
410 	return 0;
411       pcontxn=tmp;
412       if (tmp.size()==1)
413 	return 1;
414       u=(newu/var)*var;
415     }
416     res.reserve(p.size()); // it's an upper estimate, a little bit over-estimated
417     it=p.begin();
418     u=(p.front().u/var)*var;
419     for (;it!=itend;){
420       current.clear();
421       current.push_back(it->g);
422       curu=it->u;
423       ++it;
424       for (;it!=itend;++it){
425 	newu=it->u;
426 	if ( newu < u ){
427 	  break;
428 	}
429 	if (curu>newu+var2)
430 	  current.insert(current.end(),(curu-newu)/var2-1,T(0));
431 	current.push_back(it->g);
432 	curu=newu;
433       }
434       if (curu>u)
435 	current.insert(current.end(),(curu-u)/var2,T(0));
436 #ifdef TIMEOUT
437       control_c();
438 #endif
439       if (ctrl_c || interrupted || !DivRem(current,pcontxn,pminptr,modulo,tmp,reste))
440 	return 0;
441       typename vector<T>::const_iterator jt=tmp.begin(),jtend=tmp.end();
442       for (int s=int(jtend-jt)-1;jt!=jtend;++jt,--s){
443 	if (!is_zero(*jt))
444 	  res.push_back(T_unsigned<T,hashgcd_U>(*jt,u+s*var2));
445       }
446       u=(newu/var)*var;
447     }
448     return 2;
449   }
450 
451   template<class T>
pp_mod_last(vector<T_unsigned<T,hashgcd_U>> & p,const vector<int> * pminptr,int modulo,hashgcd_U var,hashgcd_U var2,vector<T> & pcontxn)452   static bool pp_mod_last(vector< T_unsigned<T,hashgcd_U> > & p,const vector<int> * pminptr,int modulo,hashgcd_U var,hashgcd_U var2,vector<T> & pcontxn){
453     vector< T_unsigned<T,hashgcd_U> > res;
454     int r=pp_mod_last(p,pminptr,modulo,var,var2,pcontxn,res);
455     if (r==0)
456       return false;
457     if (r==2)
458       p.swap(res); // p=res
459     return true;
460   }
461 
462   template<class T>
operator <(const vector<T_unsigned<T,hashgcd_U>> & v1,const vector<T_unsigned<T,hashgcd_U>> & v2)463   static bool operator < (const vector< T_unsigned<T,hashgcd_U> > & v1,const vector< T_unsigned<T,hashgcd_U> > & v2){
464     return v1.size()<v2.size();
465   }
466 
467   /*
468   unsigned degree_xn(const vector< T_unsigned<int,hashgcd_U> > & p,hashgcd_U var,hashgcd_U var2){
469     vector< T_unsigned<int,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
470     hashgcd_U degxn=0;
471     hashgcd_U u;
472     for (;it!=itend;++it){
473       u=it->u%var;
474       if (degxn<u)
475 	degxn=u;
476     }
477     return degxn/var2;
478   }
479   */
480 
481   template<class T>
degree_xn(const vector<T_unsigned<T,hashgcd_U>> & p,short int shift_var,short int shift_var2)482   static hashgcd_U degree_xn(const vector< T_unsigned<T,hashgcd_U> > & p,short int shift_var,short int shift_var2){
483     typename vector< T_unsigned<T,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end(),it1;
484     hashgcd_U degxn=0;
485     hashgcd_U u,uend;
486     for (;it!=itend;++it){
487       uend = ((it->u >> shift_var) << shift_var);
488       u = (it->u - uend) >> shift_var2 ;
489       if (!u)
490 	continue;
491       if (degxn<u)
492 	degxn=u;
493       if ((int)u>=itend-it)
494 	continue;
495       it1 = it+u;
496       if (it1->u==uend)
497 	it = it1;
498     }
499     return degxn ;
500   }
501 
502   /*
503   template<class T>
504   int degree(const vector< T_unsigned<T,hashgcd_U> > & p,
505 	      const std::vector<hashgcd_U> & vars,
506 	      index_t & res){
507     typename vector< T_unsigned<T,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
508     std::vector<hashgcd_U>::const_iterator jtbeg=vars.begin(),jtend=vars.end(),jt;
509     hashgcd_U u,ur;
510     res=index_t(jtend-jtbeg);
511     index_t::iterator ktbeg=res.begin(),ktend=res.end(),kt;
512     int totaldeg=0,current;
513     for (;it!=itend;++it){
514       u=it->u;
515       current=0;
516       for (jt=jtbeg,kt=ktbeg;jt!=jtend;++jt,++kt){
517 	ur=u%(*jt);
518 	u=u/(*jt);
519 	if (u>*kt)
520 	  *kt=u;
521 	current += u;
522 	u=ur;
523       }
524       if (current>totaldeg)
525 	totaldeg=current;
526     }
527     return totaldeg;
528   }
529   */
530 
531   template<class T>
degree(const vector<T_unsigned<T,hashgcd_U>> & p,const index_t & shift_vars,index_t & res)532   static int degree(const vector< T_unsigned<T,hashgcd_U> > & p,
533 	      const index_t & shift_vars,
534 	      index_t & res){
535     typename vector< T_unsigned<T,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
536     index_t::const_iterator jtbeg=shift_vars.begin(),jtend=shift_vars.end(),jt;
537     int dim=int(jtend-jtbeg);
538     if (dim==1){
539       int deg=it->u >> *jtbeg;
540       res.clear();
541       res.push_back(deg);
542       return deg;
543     }
544     hashgcd_U u,uq,uend,skip;
545     short int lastvar=shift_vars[shift_vars.size()-2],shift_var2=shift_vars.back();
546     res=index_t(jtend-jtbeg);
547     index_t::iterator ktbeg=res.begin(),ktend=res.end(),kt;
548     int totaldeg=0,current;
549     for (;it!=itend;){
550       u=it->u;
551       // find degree for *it and skip monomials having x1..xn-1 in common
552       uend = (u >> lastvar) << lastvar;
553       skip = (u-uend) >> shift_var2;
554       current=0;
555       // find partial and total degree
556       for (jt=jtbeg,kt=ktbeg;jt!=jtend;++jt,++kt){
557 	uq = u >> *jt;
558 	u -= uq << *jt;
559 	if ((int)uq>*kt)
560 	  *kt = uq;
561 	current += uq;
562       }
563       if (current>totaldeg)
564 	totaldeg=current;
565       if ((int)skip<itend-it && (it+skip)->u==uend){
566 	it += skip;
567 	++it;
568 	continue;
569       }
570       for (++it;it!=itend;++it){
571 	if (it->u<uend)
572 	  break;
573       }
574     }
575     return totaldeg;
576   }
577 
578   static int mod_gcd_ext(const vector< T_unsigned<vector<int>,hashgcd_U> > & p_orig,const vector< T_unsigned<vector<int>,hashgcd_U> > & q_orig,const std::vector<hashgcd_U> & vars,const vector<int> & pmin,int modulo,
579 	      vector< T_unsigned<vector<int>,hashgcd_U> > & d,
580 	      vector< T_unsigned<vector<int>,hashgcd_U> > & pcof,vector< T_unsigned<vector<int>,hashgcd_U> > & qcof,bool compute_pcof,bool compute_qcof,
581 	      int nthreads);
582 
mod_gcd(const vector<T_unsigned<vector<int>,hashgcd_U>> & p_orig,const vector<T_unsigned<vector<int>,hashgcd_U>> & q_orig,const vector<int> * pminptr,int modulo,const std::vector<hashgcd_U> & vars,vector<T_unsigned<vector<int>,hashgcd_U>> & d,vector<T_unsigned<vector<int>,hashgcd_U>> & pcof,vector<T_unsigned<vector<int>,hashgcd_U>> & qcof,bool compute_cof,int nthreads)583   bool mod_gcd(const vector< T_unsigned<vector<int>,hashgcd_U> > & p_orig,const vector< T_unsigned<vector<int>,hashgcd_U> > & q_orig,const vector<int> * pminptr,int modulo,const std::vector<hashgcd_U> & vars,
584 	      vector< T_unsigned<vector<int>,hashgcd_U> > & d,
585 	      vector< T_unsigned<vector<int>,hashgcd_U> > & pcof,vector< T_unsigned<vector<int>,hashgcd_U> > & qcof,bool compute_cof,
586 	      int nthreads){
587     return mod_gcd_ext(p_orig,q_orig,vars,*pminptr,modulo,d,pcof,qcof,compute_cof,compute_cof,nthreads)!=0;
588   }
589 
mod_gcd(const vector<T_unsigned<int,hashgcd_U>> & p_orig,const vector<T_unsigned<int,hashgcd_U>> & q_orig,const vector<int> * pminptr,int modulo,const std::vector<hashgcd_U> & vars,vector<T_unsigned<int,hashgcd_U>> & d,vector<T_unsigned<int,hashgcd_U>> & pcofactor,vector<T_unsigned<int,hashgcd_U>> & qcofactor,bool compute_cofactor,int nthreads)590   bool mod_gcd(const vector< T_unsigned<int,hashgcd_U> > & p_orig,const vector< T_unsigned<int,hashgcd_U> > & q_orig,const vector<int> * pminptr,int modulo,const std::vector<hashgcd_U> & vars, vector< T_unsigned<int,hashgcd_U> > & d, vector< T_unsigned<int,hashgcd_U> > & pcofactor, vector< T_unsigned<int,hashgcd_U> > & qcofactor,bool compute_cofactor,int nthreads){
591     return mod_gcd(p_orig,q_orig,modulo,d,pcofactor,qcofactor,vars,compute_cofactor,nthreads);
592   }
593 
594   struct modred {
595     int modulo;
596     vector<int> pmin;
modredgiac::modred597     modred(int m,const vector<int> & p):modulo(m),pmin(p) {}
modredgiac::modred598     modred():modulo(0),pmin(0) {}
599   };
600 
is_zero(const modred & r)601   static bool is_zero(const modred & r){
602     return r.modulo==0;
603   }
604 
make_modulo(const vector<int> * pminptr,int modulo,int)605   static int make_modulo(const vector<int> * pminptr,int modulo,int){
606     return modulo;
607   }
608 
make_modulo(const vector<int> * pminptr,int modulo,vector<int>)609   static modred make_modulo(const vector<int> * pminptr,int modulo,vector<int>){
610     return modred(modulo,*pminptr);
611   }
612 
613   struct Modred {
614     int modulo;
615     vecteur pmin;
Modredgiac::Modred616     Modred(int m,const vecteur & p):modulo(m),pmin(p) {}
Modredgiac::Modred617     Modred():modulo(0),pmin(0) {}
618   };
619 
is_zero(const Modred & r)620   static bool is_zero(const Modred & r){
621     return r.modulo==0;
622   }
623 
624   // extract modular content of p wrt to all but the last variable
625   // returns 0 failure
626   // 1 on success, res not computed
627   // 2 on success, res computed
628   template<class T>
pp_mod(const vector<T_unsigned<T,hashgcd_U>> & p,const vector<int> * pminptr,int modulo,const std::vector<hashgcd_U> & vars,vector<T_unsigned<T,hashgcd_U>> & pcont,int nthreads,vector<T_unsigned<T,hashgcd_U>> & res)629   static int pp_mod(const vector< T_unsigned<T,hashgcd_U> > & p,const vector<int> * pminptr,int modulo,const std::vector<hashgcd_U> & vars,vector< T_unsigned<T,hashgcd_U> > & pcont,int nthreads,vector< T_unsigned<T,hashgcd_U> > & res){
630 #ifdef NO_TEMPLATE_MULTGCD
631     return 0;
632 #else
633     typename vector< T_unsigned<T,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
634     pcont.clear();
635     pcont.push_back(T_unsigned<T,hashgcd_U>(make_unit(T(0)),0));
636     if (it==itend || vars.empty())
637       return 1;
638     // hashgcd_U degxnu=0;
639     hashgcd_U u,u0,var=vars[vars.size()-2],var2=vars.back();
640     short int shiftvar=find_shift(var),shiftvar2=find_shift(var2);
641     hashgcd_U degxn = degree_xn(p,shiftvar,shiftvar2);
642 #ifndef VISUALC
643     int nterms[degxn+1];
644     bool nonzero[degxn+1];
645     for (int i=0;i<=degxn;++i){
646       nterms[i]=0;
647       nonzero[i]=false;
648     }
649 #else
650     vector<int> nterms(degxn+1);
651     vector<bool> nonzero(degxn+1,false); // number of non constant terms
652 #endif
653     int pos;
654     for (it=p.begin();it!=itend;++it){
655       u = it->u;
656       pos = (u%var) >> shiftvar2;
657       nonzero[pos]=true;
658       if (u>>shiftvar)
659 	++nterms[pos];
660     }
661     for (int i=degxn;i>=0;--i){
662       if (!nterms[i] && nonzero[i]) // all terms would be constant in vp[i]
663 	return 1;
664     }
665     vector< vector< T_unsigned<T,hashgcd_U> > > vp(degxn+1);
666     for (int i=degxn;i>=0;--i){
667       vp[i].reserve(nterms[i]+1);
668     }
669     for (it=p.begin();it!=itend;++it){
670       u = it->u;
671       u0 = (u >> shiftvar) << shiftvar;
672       vp[(u-u0)>>shiftvar2].push_back(T_unsigned<T,hashgcd_U>(it->g, u0));
673     }
674     // sort vp by size
675     sort(vp.begin(),vp.end());
676     // compute gcd
677     unsigned int i=0;
678     for (;i<=degxn;++i){
679       if (!vp[i].empty()){
680 	pcont=vp[i];
681 	break;
682       }
683     }
684     if (pcont.empty())
685       CERR << "empty" << '\n';
686     std::vector<hashgcd_U> varsn(vars);
687     varsn.pop_back();
688     vector< T_unsigned<T,hashgcd_U> > pcof,qcof; // not used (false in mod_gcd)
689     for (++i;i<=degxn;++i){
690       if (pcont.size()==1 && pcont.front().u==0)
691 	return 1;
692 #ifdef TIMEOUT
693       control_c();
694 #endif
695       if (ctrl_c || interrupted || !mod_gcd(pcont,vp[i],pminptr,modulo,varsn,pcont,pcof,qcof,false,nthreads))
696 	return 0;
697     }
698     if (pcont.size()==1 && pcont.front().u==0)
699       return 1;
700     vector< T_unsigned<T,hashgcd_U> > tmpres,rem;
701     hashdivrem(p,pcont,tmpres,rem,vars,make_modulo(pminptr,modulo,T(0)),0,false);
702     res.swap(tmpres);
703     return 2;
704 #endif // NO_TEMPLATE_MULTGCD
705   }
706 
707   template<class T>
pp_mod(vector<T_unsigned<T,hashgcd_U>> & p,const vector<int> * pminptr,int modulo,const std::vector<hashgcd_U> & vars,vector<T_unsigned<T,hashgcd_U>> & pcont,int nthreads)708   static bool pp_mod(vector< T_unsigned<T,hashgcd_U> > & p,const vector<int> * pminptr,int modulo,const std::vector<hashgcd_U> & vars,vector< T_unsigned<T,hashgcd_U> > & pcont,int nthreads){
709     vector< T_unsigned<T,hashgcd_U> > res;
710     int r=pp_mod(p,pminptr,modulo,vars,pcont,nthreads,res);
711     if (r==0)
712       return false;
713     if (r==2)
714       p.swap(res);
715     return true;
716   }
717 
718   // fast check if p is primitive with respect to the main var
719   // p main var is y, inner var is x
is_front_primitive(vector<vector<int>> & p,int modulo)720   static bool is_front_primitive(vector< vector<int> > & p,int modulo){
721     vector< vector<int> >::iterator it=p.begin(),itend=p.end();
722     int degy=int(itend-it)-1;
723     vector<int> degrees;
724     int degs=0,d;
725     for (it=p.begin();it!=itend;++it,--degy){
726       d=int(it->size());
727       // there is a x^d*y^degy term -> set degree of x^0 to x^d to degy at least
728       if (d>degs){
729 	degrees.insert(degrees.end(),d-degs,degy);
730 	degs=d;
731       }
732     }
733     vector<int>::iterator jt=degrees.begin(),jtend=degrees.end();
734     for (;jt!=jtend;++jt){
735       if (!*jt)
736 	return true;
737     }
738     return false;
739   }
740 
741   // eval p at x with respect to the last variable
742   // keep only terms of degree <= maxdeg with respect to the main variable
horner(const vector<T_unsigned<int,hashgcd_U>> & p,int x,const std::vector<hashgcd_U> & vars,vector<T_unsigned<int,hashgcd_U>> & px,int modulo,int maxdeg)743   static bool horner(const vector< T_unsigned<int,hashgcd_U> > & p,int x,const std::vector<hashgcd_U> & vars,vector< T_unsigned<int,hashgcd_U> > & px,int modulo,int maxdeg){
744     hashgcd_U var=vars[vars.size()-2];
745     hashgcd_U var2=vars.back();
746     vector< T_unsigned<int,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end(),it1,it2;
747     vector<hashgcd_U>::const_iterator jtend=vars.end()-1;
748     hashgcd_U ucur,uend;
749     if (maxdeg>=0){
750       uend=(maxdeg+1)*vars.front();
751       // dichotomy to find start position
752       int pos1=0,pos2=int(itend-it),pos;
753       for (;pos2-pos1>1;){
754 	pos=(pos1+pos2)/2;
755 	if ((it+pos)->u<uend)
756 	  pos2=pos;
757 	else
758 	  pos1=pos;
759       }
760       it += pos1;
761       if (it->u>=uend)
762 	++it;
763     }
764     if (x==0){
765       px.clear();
766       for (;it!=itend;){
767 	ucur=it->u;
768 	uend=(ucur/var)*var;
769 	if (ucur==uend){
770 	  register int g=smod(it->g,modulo);
771 	  if (g!=0)
772 	    px.push_back(T_unsigned<int,hashgcd_U>(g,uend));
773 	  ++it;
774 	  continue;
775 	}
776 	register int nterms = (ucur-uend)/var2;
777 	if (nterms<itend-it && (it+nterms)->u==uend){
778 	  it += nterms;
779 	  register int g=smod(it->g,modulo);
780 	  if (g!=0)
781 	    px.push_back(T_unsigned<int,hashgcd_U>(g,uend));
782 	  ++it;
783 	  continue;
784 	}
785 	for (++it;it!=itend;++it){
786 	  if (it->u<=uend){
787 	    if (it->u==uend){
788 	      register int g=smod(it->g,modulo);
789 	      if (g!=0)
790 		px.push_back(T_unsigned<int,hashgcd_U>(g,uend));
791 	      ++it;
792 	    }
793 	    break;
794 	  }
795 	}
796       }
797       return true;
798     }
799     vector< T_unsigned<int,hashgcd_U> >::iterator kt=px.begin(),ktend=px.end();
800     for (;it!=itend;){
801       ucur=it->u;
802       uend=(ucur/var)*var;
803       if (ucur==uend){
804 	if (kt!=ktend){
805 	  *kt=*it;
806 	  ++kt;
807 	}
808 	else
809 	  px.push_back(*it);
810 	++it;
811 	continue;
812       }
813       int g=0;
814       int nterms=(ucur-uend)/var2+1;
815       if (x==1 && nterms < RAND_MAX/modulo ){
816 	for (;it!=itend;++it){
817 	  if (it->u<uend){
818 	    g=smod(g,modulo);
819 	    if (g!=0){
820 	      if (kt!=ktend){
821 		*kt=T_unsigned<int,hashgcd_U>(g,uend);
822 		++kt;
823 	      }
824 	      else
825 		px.push_back(T_unsigned<int,hashgcd_U>(g,uend));
826 	    }
827 	    break;
828 	  }
829 	  else
830 	    g += it->g;
831 	}
832 	if (it==itend){
833 	  g=smod(g,modulo);
834 	  if (g!=0){
835 	    if (kt!=ktend){
836 	      *kt=T_unsigned<int,hashgcd_U>(g,uend);
837 	      ++kt;
838 	    }
839 	    else
840 	      px.push_back(T_unsigned<int,hashgcd_U>(g,uend));
841 	  }
842 	}
843 	continue;
844       }
845       else {
846 	// Check if the next group of monomials is dense wrt to xn
847 	it1=it+nterms;
848 	if (//false &&
849 	    nterms<itend-it && (it1-1)->u==uend
850 	    ){
851 	  if (modulo<=46340){
852 	    if (x>=-14 && x<=14){
853 	      if (x>=-8 && x<=8){
854 		it2=it+5*((it1-it)/5);
855 		for (;it!=it2;){
856 		  g *= x;
857 		  g += it->g;
858 		  ++it;
859 		  g *= x;
860 		  g += it->g;
861 		  ++it;
862 		  g *= x;
863 		  g += it->g;
864 		  ++it;
865 		  g *= x;
866 		  g += it->g;
867 		  ++it;
868 		  g *= x;
869 		  g += it->g;
870 		  g %= modulo;
871 		  ++it;
872 		}
873 	      }
874 	      else {
875 		it2=it+4*((it1-it)/4);
876 		for (;it!=it2;){
877 		  g *= x;
878 		  g += it->g;
879 		  ++it;
880 		  g *= x;
881 		  g += it->g;
882 		  ++it;
883 		  g *= x;
884 		  g += it->g;
885 		  ++it;
886 		  g *= x;
887 		  g += it->g;
888 		  g %= modulo;
889 		  ++it;
890 		}
891 	      }
892 	    }
893 	    else {
894 	      if (x>=-35 && x<=35){
895 		it2=it+3*((it1-it)/3);
896 		for (;it!=it2;){
897 		  g *= x;
898 		  g += it->g;
899 		  ++it;
900 		  g *= x;
901 		  g += it->g;
902 		  ++it;
903 		  g *= x;
904 		  g += it->g;
905 		  g %= modulo;
906 		  ++it;
907 		}
908 	      }
909 	    }
910 	    for (;it!=it1;++it){
911 	      g = (g*x+it->g)%modulo;
912 	    }
913 	  } // end if (modulo<46430)
914 	  else { // modulo>=46430, using longlong
915 	    if (x>=-84 && x<=84){
916 	      longlong G=g;
917 	      it2=it+5*((it1-it)/5);
918 	      for (;it!=it2;){
919 		G *= x;
920 		G += it->g;
921 		++it;
922 		G *= x;
923 		G += it->g;
924 		++it;
925 		G *= x;
926 		G += it->g;
927 		++it;
928 		G *= x;
929 		G += it->g;
930 		++it;
931 		G *= x;
932 		G += it->g;
933 		G %= modulo;
934 		++it;
935 	      }
936 	      for (;it!=it1;++it){
937 		G *=x;
938 		G += it->g;
939 	      }
940 	      g=G%modulo;
941 	    }
942 	    else {
943 	      for (;it!=it1;++it){
944 		g = (g*longlong(x)+it->g)%modulo;
945 	      }
946 	    }
947 	  }
948 	  g=smod(g,modulo);
949 	  if (g!=0){
950 	    if (kt!=ktend){
951 	    *kt=T_unsigned<int,hashgcd_U>(g,uend);
952 	    ++kt;
953 	    }
954 	    else
955 	      px.push_back(T_unsigned<int,hashgcd_U>(g,uend));
956 	  }
957 	  continue;
958 	}
959 	if (modulo>=46340){
960 	  for (;it!=itend;++it){
961 	    const hashgcd_U & u=it->u;
962 	    if (u<uend){
963 	      if (g!=0){
964 		g = smod(g*longlong(powmod(x,(ucur-uend)/var2,modulo)),modulo);
965 		if (g!=0){
966 		  if (kt!=ktend){
967 		    *kt=T_unsigned<int,hashgcd_U>(g,uend);
968 		    ++kt;
969 		  }
970 		  else
971 		    px.push_back(T_unsigned<int,hashgcd_U>(g,uend));
972 		}
973 	      }
974 	      break;
975 	    }
976 	    if (ucur-u==var2)
977 	      g = (g*longlong(x)+ it->g)%modulo;
978 	    else
979 	      g = (g*longlong(powmod(x,(ucur-u)/var2,modulo))+ it->g)%modulo;
980 	    ucur=u;
981 	  } // end for
982 	} // end if modulo>=46340
983 	else {
984 	  for (;it!=itend;++it){
985 	    const hashgcd_U & u=it->u;
986 	    if (u<uend){
987 	      if (g!=0){
988 		g = smod(g*powmod(x,(ucur-uend)/var2,modulo),modulo);
989 		if (g!=0){
990 		  if (kt!=ktend){
991 		    *kt=T_unsigned<int,hashgcd_U>(g,uend);
992 		    ++kt;
993 		  }
994 		  else
995 		    px.push_back(T_unsigned<int,hashgcd_U>(g,uend));
996 		}
997 	      }
998 	      break;
999 	    }
1000 	    if (ucur-u==var2)
1001 	      g = (g*x+ it->g)%modulo;
1002 	    else
1003 	      g = (g*powmod(x,(ucur-u)/var2,modulo)+ it->g)%modulo;
1004 	    ucur=u;
1005 	  } // end for
1006 	}
1007       } // end else x=1
1008       if (it==itend){
1009 	if (g!=0){
1010 	  g = smod(g*longlong(powmod(x,(ucur-uend)/var2,modulo)),modulo);
1011 	  if (g!=0){
1012 	    if (kt!=ktend){
1013 	      *kt=T_unsigned<int,hashgcd_U>(g,uend);
1014 	      ++kt;
1015 	    }
1016 	    else
1017 	      px.push_back(T_unsigned<int,hashgcd_U>(g,uend));
1018 	  }
1019 	}
1020       }
1021     }
1022     if (kt!=ktend)
1023       px.erase(kt,ktend);
1024     return true;
1025   }
1026 
1027   // v <- v*k % m
mulmod(vector<int> & v,int k,int m)1028   void mulmod(vector<int> & v,int k,int m){
1029     if (k==1)
1030       return;
1031     vector<int>::iterator it=v.begin(),itend=v.end();
1032     for (;it!=itend;++it){
1033       type_operator_times_reduce(*it,k,*it,m);
1034       // *it = ((*it)*k)%m;
1035     }
1036   }
1037 
1038   // v <- v*k % m
mulmod(vector<vector<int>> & v,int k,int m)1039   void mulmod(vector< vector<int> > & v,int k,int m){
1040     if (k==1)
1041       return;
1042     vector< vector<int> >::iterator it=v.begin(),itend=v.end();
1043     for (;it!=itend;++it){
1044       mulmod(*it,k,m);
1045     }
1046   }
1047 
1048 
1049   // v <- v+w % m
addmod(vector<int> & v,const vector<int> & w,int m)1050   void addmod(vector<int> & v,const vector<int> & w,int m){
1051     vector<int>::const_iterator jt=w.begin(),jtend=w.end();
1052     vector<int>::iterator it=v.begin(),itend=v.end();
1053     int ws=int(jtend-jt),vs=int(v.size());
1054     if (ws>vs){
1055       if ((int)v.capacity()<ws){
1056 	vector<int> tmp(ws);
1057 	copy(v.begin(),v.end(),tmp.begin()+ws-vs);
1058 	swap(v,tmp);
1059       }
1060       else {
1061 	v.insert(v.begin(),ws-vs,0);
1062       }
1063       it=v.begin();
1064       itend=v.end();
1065     }
1066     for (it=itend-ws;it!=itend;++jt,++it){
1067       *it = (*it+*jt)%m;
1068     }
1069     // trim resulting polynomial
1070     for (it=v.begin();it!=itend;++it){
1071       if (*it)
1072 	break;
1073     }
1074     if (it!=v.begin())
1075       v.erase(v.begin(),it);
1076   }
1077 
1078   // v <- v+w % m
addmod(vector<vector<int>> & v,const vector<vector<int>> & w,int m)1079   void addmod(vector< vector<int> > & v,const vector< vector<int> > & w,int m){
1080     vector< vector<int> >::iterator it=v.begin(),itend=v.end();
1081     vector< vector<int> >::const_iterator jt=w.begin(),jtend=w.end();
1082     int addv=int(jtend-jt)-int(itend-it);
1083     if (addv>0){
1084       v.insert(v.begin(),addv,vector<int>(0));
1085       it=v.begin();
1086       itend=v.end();
1087     }
1088     for (it=itend-(jtend-jt);it!=itend;++jt,++it){
1089       addmod(*it,*jt,m);
1090     }
1091   }
1092 
1093   // v <- v+w % m
1094   // requires m<=2^30 to avoid possible overflow
addmod(vecteur & v,const vecteur & w,int m)1095   static void addmod(vecteur & v,const vecteur & w,int m){
1096     vecteur::const_iterator jt=w.begin(),jtend=w.end();
1097     vecteur::iterator it=v.begin(),itend=v.end();
1098     int ws=int(jtend-jt),vs=int(v.size());
1099     if (ws>vs){
1100       if ((int)v.capacity()<ws){
1101 	vecteur tmp(ws);
1102 	copy(v.begin(),v.end(),tmp.begin()+ws-vs);
1103 	swap(v,tmp);
1104       }
1105       else {
1106 	v.insert(v.begin(),ws-vs,0);
1107       }
1108       it=v.begin();
1109       itend=v.end();
1110     }
1111     for (it=itend-ws;it!=itend;++jt,++it){
1112       *it = smod(*it+*jt,m);
1113     }
1114     // trim resulting polynomial
1115     for (it=v.begin();it!=itend;++it){
1116       if (!is_zero(*it))
1117 	break;
1118     }
1119     if (it!=v.begin())
1120       v.erase(v.begin(),it);
1121   }
1122 
1123   // v <- v-w % m
submod(vector<int> & v,const vector<int> & w,int m)1124   void submod(vector<int> & v,const vector<int> & w,int m){
1125     vector<int>::iterator it=v.begin(),itend=v.end();
1126     vector<int>::const_iterator jt=w.begin(),jtend=w.end();
1127     int addv=int(jtend-jt)-int(itend-it);
1128     if (addv>0){
1129       v.insert(v.begin(),addv,0);
1130       it=v.begin();
1131       itend=v.end();
1132     }
1133     for (it=itend-(jtend-jt);it!=itend;++jt,++it){
1134       *it = (*it-longlong(*jt))%m;
1135     }
1136     for (it=v.begin();it!=itend;++it){
1137       if (*it)
1138 	break;
1139     }
1140     if (it!=v.begin())
1141       v.erase(v.begin(),it);
1142   }
1143 
1144   // v <- w-v % m
submodneg(vector<int> & v,const vector<int> & w,int m)1145   void submodneg(vector<int> & v,const vector<int> & w,int m){
1146     vector<int>::iterator it=v.begin(),itend=v.end();
1147     vector<int>::const_iterator jt=w.begin(),jtend=w.end();
1148     int addv=int(jtend-jt)-int(itend-it);
1149     if (addv>0){
1150       v.insert(v.begin(),addv,0);
1151       it=v.begin();
1152       itend=v.end();
1153     }
1154     else {
1155       itend -= jtend-jt;
1156       for (;it!=itend;++it)
1157 	*it = -*it;
1158       itend += jtend-jt;
1159     }
1160     for (;it!=itend;++jt,++it){
1161 #if 1
1162       int a=*it,b=*jt;
1163       a += (a>>31)&m;
1164       b += (b>>31)&m;
1165       *it = b-a;
1166 #else
1167       *it = (*jt-longlong(*it))%m;
1168 #endif
1169     }
1170     for (it=v.begin();it!=itend;++it){
1171       if (*it)
1172 	break;
1173     }
1174     if (it!=v.begin())
1175       v.erase(v.begin(),it);
1176   }
1177 
1178   // v <- k*(v-w) % m
mulsubmod(int k,vector<int> & v,const vector<int> & w,int m)1179   static void mulsubmod(int k,vector<int> & v,const vector<int> & w,int m){
1180     vector<int>::iterator it=v.begin(),itend=v.end();
1181     vector<int>::const_iterator jt=w.begin(),jtend=w.end();
1182     int addv=int(jtend-jt)-int(itend-it);
1183     if (addv>0){
1184       v.insert(v.begin(),addv,0);
1185       it=v.begin();
1186       itend=v.end();
1187     }
1188     itend -= (jtend-jt);
1189     if (m<=46340){
1190       if (2*k>m)
1191 	k -= m;
1192       for (;it!=itend;++it){
1193 	*it = ((*it)*k)%m;
1194       }
1195       for (itend=v.end();it!=itend;++jt,++it){
1196 	*it = ((*it-*jt)*k)%m;
1197       }
1198     }
1199     else {
1200       for (;it!=itend;++it){
1201 	type_operator_times_reduce(*it,k,*it,m);
1202 	// *it = ((*it)*k)%m;
1203       }
1204       for (itend=v.end();it!=itend;++jt,++it){
1205 	*it -= *jt;
1206 	type_operator_times_reduce(*it,k,*it,m);
1207 	// *it = ((*it)*k)%m;
1208       }
1209     }
1210     for (it=v.begin();it!=itend;++it){
1211       if (*it)
1212 	break;
1213     }
1214     if (it!=v.begin())
1215       v.erase(v.begin(),it);
1216   }
1217 
1218   // eval p at x with respect to all but the last variable
1219   template<class T>
horner(const std::vector<T_unsigned<T,hashgcd_U>> & p,const std::vector<int> & x,const std::vector<hashgcd_U> & vars,std::vector<T> & px,int modulo)1220   static bool horner(const std::vector< T_unsigned<T,hashgcd_U> > & p,const std::vector<int> & x,const std::vector<hashgcd_U> & vars,std::vector<T> & px,int modulo){
1221     int s=int(x.size());
1222     // int xback=x.back();
1223     int vs=int(vars.size());
1224     if (s+1!=vs || vs<2)
1225       return false; // setdimerr();
1226     hashgcd_U var=vars[vs-2],var2=vars.back();
1227     int shift_var=find_shift(var),shift_var2=find_shift(var2);
1228     typename vector< T_unsigned<T,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
1229     if (is_zero(x)){
1230       int pos1=0,pos2=int(itend-it),pos;
1231       for (;pos2-pos1>1;){
1232 	pos=(pos1+pos2)/2;
1233 	if ((it+pos)->u<var)
1234 	  pos2=pos;
1235 	else
1236 	  pos1=pos;
1237       }
1238       it += pos1;
1239       if (it->u>=var)
1240 	++it;
1241       if (it==itend)
1242 	px.clear();
1243       else {
1244 	int pxdeg = it->u >> shift_var2;
1245 	px=vector<T>(pxdeg+1);
1246 	for (;it!=itend;++it){
1247 	  px[pxdeg - (it->u >> shift_var2)]=it->g;
1248 	}
1249       }
1250     }
1251     else {
1252       int pxdeg=degree_xn(p,shift_var,shift_var2);
1253       px=vector<T>(pxdeg+1);
1254       vector<hashgcd_U>::const_iterator jtbeg=vars.begin(),jtend=vars.end(),jt;
1255       --jtend;
1256       vector<int>::const_iterator ktbeg=x.begin(),kt;
1257       hashgcd_U u,oldu=0;
1258       int oldfact=0;
1259       int inverse=x.back()?invmod(x.back(),modulo):0;
1260       for (;it!=itend;){
1261 	// group next monomials with same powers in x1..xn-1
1262 	u=(it->u/var)*var;
1263 	int tmpdeg=(it->u-u)/var2;
1264 	vector<T> tmp(tmpdeg+1);
1265 	for (;;++it){
1266 	  if (it==itend || it->u<u){
1267 	    int fact=1;
1268 	    if (inverse && oldu-u==var && oldfact){
1269 	      fact = (longlong(oldfact)*inverse)%modulo;
1270 	      oldu=u;
1271 	    }
1272 	    else {
1273 	      oldu=u;
1274 	      for (jt=jtbeg,kt=ktbeg;jt!=jtend;++jt,++kt){
1275 		// px=px*powmod(*kt,u / *jt,modulo);
1276 		fact = (longlong(fact)*powmod(*kt,u / *jt,modulo))%modulo;
1277 		u = u % *jt;
1278 	      }
1279 	    }
1280 	    oldfact=fact;
1281 	    mulmod(tmp,fact,modulo); // inlined in modpoly.cc
1282 	    addmod(px,tmp,modulo);
1283 	    break;
1284 	  }
1285 	  tmp[tmpdeg-(it->u-u)/var2]=it->g;
1286 	}
1287       }
1288     } // end else is_zero(x)
1289     // trim px
1290     typename vector<T>::iterator lt=px.begin(),ltend=px.end();
1291     for (;lt!=ltend;++lt){
1292       if (!is_zero(*lt))
1293 	break;
1294     }
1295     if (lt!=px.begin())
1296       px.erase(px.begin(),lt);
1297     return true;
1298   }
1299 
1300   template<class T>
convert_back(const vector<T> & v,hashgcd_U var,vector<T_unsigned<T,hashgcd_U>> & p)1301   static void convert_back(const vector<T> & v,hashgcd_U var,vector< T_unsigned<T,hashgcd_U> > & p){
1302     p.clear();
1303     typename vector<T>::const_iterator it=v.begin(),itend=v.end();
1304     unsigned s=unsigned(itend-it);
1305     p.reserve(s);
1306     hashgcd_U u=var*(s-1);
1307     for (;it!=itend;u-=var,++it){
1308       if (!is_zero(*it))
1309 	p.push_back(T_unsigned<T,hashgcd_U>(*it,u));
1310     }
1311   }
1312 
convert_back(const vector<vector<int>> & v,hashgcd_U varxn,hashgcd_U var2,vector<T_unsigned<int,hashgcd_U>> & p)1313   static void convert_back(const vector< vector<int> > & v,hashgcd_U varxn,hashgcd_U var2,vector< T_unsigned<int,hashgcd_U> > & p){
1314     vector< vector<int> >::const_iterator jt=v.begin(),jtend=v.end();
1315     size_t S=0;
1316     for (;jt!=jtend;++jt){
1317       vector<int>::const_iterator it=jt->begin(),itend=jt->end();
1318       for (;it!=itend;++it){
1319 	S += (*it!=0);
1320       }
1321     }
1322     p.clear();
1323     p.reserve(S);
1324     for (jt=v.begin();jt!=jtend;++jt){
1325       vector<int>::const_iterator it=jt->begin(),itend=jt->end();
1326       unsigned s=unsigned(itend-it);
1327       hashgcd_U u=var2*(s-1)+varxn*(unsigned(jtend-jt)-1);
1328       for (;it!=itend;u-=var2,++it){
1329 	if (*it!=0)
1330 	  p.push_back(T_unsigned<int,hashgcd_U>(*it,u));
1331       }
1332     }
1333   }
1334 
convert(const vector<T_unsigned<int,hashgcd_U>> & p,hashgcd_U var,vector<int> & v,int modulo)1335   static void convert(const vector< T_unsigned<int,hashgcd_U> > & p,hashgcd_U var,vector<int> & v,int modulo){
1336     v.clear();
1337     vector< T_unsigned<int,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
1338     if (it==itend)
1339       return;
1340     hashgcd_U u=it->u;
1341     unsigned s=u/var;
1342     v=vector<int>(s+1);
1343     for (;it!=itend;++it){
1344       v[s-it->u/var]=it->g<0?it->g+modulo:it->g;
1345     }
1346   }
1347 
1348 #if 0
1349   static void convert(const vector< T_unsigned<int,hashgcd_U> > & p,short int var,vector<int> & v,int modulo){
1350     vector< T_unsigned<int,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
1351     if (it==itend){
1352       v.clear();
1353       return;
1354     }
1355     hashgcd_U u=it->u;
1356     unsigned s=u >> var;
1357     if (v.size()==s+1)
1358       fill(v.begin(),v.end(),0);
1359     else
1360       v=vector<int>(s+1);
1361     for (;it!=itend;++it){
1362       v[s-(it->u >> var)]=it->g<0?it->g+modulo:it->g;
1363     }
1364   }
1365 #endif
1366 
1367   /*
1368   void convert(const vector< T_unsigned<int,hashgcd_U> > & p,hashgcd_U var,vector<int> & v){
1369     v.clear();
1370     vector< T_unsigned<int,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
1371     if (it==itend)
1372       return;
1373     hashgcd_U u=it->u,prevu=u;
1374     unsigned s=u/var;
1375     v.reserve(s+1);
1376     v.push_back(it->g);
1377     for (++it;it!=itend;++it){
1378       u=it->u;
1379       prevu -= var;
1380       if (u==prevu)
1381 	v.push_back(it->g);
1382       else {
1383 	v.insert(v.end(),(prevu-u)/var,0);
1384 	v.push_back(it->g);
1385 	prevu=u;
1386       }
1387     }
1388   }
1389   */
1390   // Find non zeros coeffs of p
1391   template<class T>
find_nonzero(const vector<T> & p,index_t & res)1392   static int find_nonzero(const vector<T> & p,index_t & res){
1393     res.clear();
1394     typename vector<T>::const_iterator it=p.begin(),itend=p.end();
1395     if (it==itend)
1396       return 0;
1397     int nzeros=0;
1398     for (;it!=itend;++it){
1399       bool test=is_zero(*it);
1400       res.push_back(test?0:1);
1401       if (test)
1402 	++nzeros;
1403     }
1404     return nzeros;
1405   }
1406 
1407   template<class T>
lcoeff(const vector<T_unsigned<T,hashgcd_U>> & p,hashgcd_U var,hashgcd_U var2,vector<T> & lp)1408   static hashgcd_U lcoeff(const vector< T_unsigned<T,hashgcd_U> > & p,hashgcd_U var,hashgcd_U var2,vector<T> & lp){
1409     lp.clear();
1410     typename vector< T_unsigned<T,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
1411     if (it==itend)
1412       return 0;
1413     hashgcd_U u=it->u;
1414     int deg=(u%var)/var2;
1415     lp.resize(deg+1);//lp=vector<T>(deg+1);
1416     u=(u/var)*var;
1417     for (;it!=itend;++it){
1418       if (it->u<u)
1419 	break;
1420       lp[deg-(it->u%var)/var2]=it->g;
1421     }
1422     return u;
1423   }
1424 
smod(const std::vector<int> & v,int modulo)1425   static std::vector<int> smod(const std::vector<int> & v,int modulo){
1426     std::vector<int> res(v);
1427     std::vector<int>::iterator it=res.begin(),itend=res.end();
1428     for (;it!=itend;++it){
1429       *it = smod(*it,modulo);
1430     }
1431     if (res.empty() || res.front())
1432       return res;
1433     for (it=res.begin();it!=itend;++it){
1434       if (*it)
1435 	break;
1436     }
1437     return std::vector<int>(it,itend);
1438   }
1439 
hornermod(const vector<int> & v,int alpha,int modulo,bool unsig)1440   int hornermod(const vector<int> & v,int alpha,int modulo,bool unsig){
1441     vector<int>::const_iterator it=v.begin(),itend=v.end(),it0;
1442     if (!alpha)
1443       return it==itend?0:v.back();
1444     int res=0;
1445     if (alpha==1 && (itend-it)<RAND_MAX/modulo){
1446       for (;it!=itend;++it)
1447 	res += *it;
1448       return smod(res,modulo);
1449     }
1450     if (alpha==-1 && (itend-it)<RAND_MAX/modulo){
1451       for (;it!=itend;++it)
1452 	res = *it - res;
1453       return smod(res,modulo);
1454     }
1455     if (modulo<46340){
1456       if (alpha>=-8 && alpha<=8){
1457 	it0=it+5*((itend-it)/5);
1458 	for (;it!=it0;){
1459 	  res *= alpha;
1460 	  res += *it;
1461 	  ++it;
1462 	  res *= alpha;
1463 	  res += *it;
1464 	  ++it;
1465 	  res *= alpha;
1466 	  res += *it;
1467 	  ++it;
1468 	  res *= alpha;
1469 	  res += *it;
1470 	  ++it;
1471 	  res *= alpha;
1472 	  res += *it;
1473 	  res %= modulo;
1474 	  ++it;
1475 	}
1476 	for (;it!=itend;++it){
1477 	  res *= alpha;
1478 	  res += *it;
1479 	}
1480 	return smod(res,modulo);
1481       }
1482       if (alpha>=-14 && alpha<=14){
1483 	it0=it+4*((itend-it)/4);
1484 	for (;it!=it0;){
1485 	  res *= alpha;
1486 	  res += *it;
1487 	  ++it;
1488 	  res *= alpha;
1489 	  res += *it;
1490 	  ++it;
1491 	  res *= alpha;
1492 	  res += *it;
1493 	  ++it;
1494 	  res *= alpha;
1495 	  res += *it;
1496 	  res %= modulo;
1497 	  ++it;
1498 	}
1499 	for (;it!=itend;++it){
1500 	  res *= alpha;
1501 	  res += *it;
1502 	}
1503 	return smod(res,modulo);
1504       }
1505       if (alpha>=-35 && alpha<=35){
1506 	it0=it+3*((itend-it)/3);
1507 	for (;it!=it0;){
1508 	  res *= alpha;
1509 	  res += *it;
1510 	  ++it;
1511 	  res *= alpha;
1512 	  res += *it;
1513 	  ++it;
1514 	  res *= alpha;
1515 	  res += *it;
1516 	  res %= modulo;
1517 	  ++it;
1518 	}
1519 	for (;it!=itend;++it){
1520 	  res *= alpha;
1521 	  res += *it;
1522 	}
1523 	return smod(res,modulo);
1524       }
1525       if (alpha>=-214 && alpha<=214){
1526 	it0=it+2*((itend-it)/2);
1527 	for (;it!=it0;){
1528 	  res *= alpha;
1529 	  res += *it;
1530 	  ++it;
1531 	  res *= alpha;
1532 	  res += *it;
1533 	  res %= modulo;
1534 	  ++it;
1535 	}
1536 	for (;it!=itend;++it){
1537 	  res *= alpha;
1538 	  res += *it;
1539 	}
1540 	return smod(res,modulo);
1541       }
1542     } // if (modulo<46430)
1543     else {
1544       longlong Res=res;
1545       if (alpha>=-8 && alpha<=8){
1546 	it0=it+5*((itend-it)/5);
1547 	for (;it!=it0;){
1548 	  Res *= alpha;
1549 	  Res += *it;
1550 	  ++it;
1551 	  Res *= alpha;
1552 	  Res += *it;
1553 	  ++it;
1554 	  Res *= alpha;
1555 	  Res += *it;
1556 	  ++it;
1557 	  Res *= alpha;
1558 	  Res += *it;
1559 	  ++it;
1560 	  Res *= alpha;
1561 	  Res += *it;
1562 	  Res %= modulo;
1563 	  ++it;
1564 	}
1565 	for (;it!=itend;++it){
1566 	  Res *= alpha;
1567 	  Res += *it;
1568 	}
1569 	return smod(Res,modulo);
1570       } // end if alpha>=-84 and alpha<=84
1571     } // end else (modulo>46430)
1572 #if defined _I386_ && !defined x86_64
1573     if (unsig){
1574       if (alpha<0)
1575 	alpha += modulo;
1576       // it va dans ecx, itend dans ebx, modulo dans edi, alpha dans esi
1577       // eax::edx produit et division, eax contient res,
1578       asm volatile("movl $0x0,%%eax;\n\t"
1579 		   "cmpl %%ecx,%%ebx;\n\t"
1580 		   "je .Lend%=\n"
1581 		   ".Lloop%=:\t"
1582 		   "imul %%esi;\n\t" /* res<-res*alpha */
1583 		   "addl (%%ecx),%%eax;\n\t"
1584 		   "adcl $0x0,%%edx; \n\t" /* res += *it */
1585 		   "idivl %%edi; \n\t"  /* res %= modulo */
1586 		   "movl %%edx,%%eax; \n\t"
1587 		   "addl $4,%%ecx; \n\t" /* ++ *it */
1588 		   "cmpl %%ecx,%%ebx;\n\t" /* it==itend */
1589 		   "jne .Lloop%=\n"
1590 		   ".Lend%=:\t"
1591 		   :"=a"(res)
1592 		   :"c"(it),"b"(itend),"D"(modulo),"S"(alpha)
1593 		   :"%edx"
1594 		   );
1595       if (res>modulo)
1596 	return res-modulo;
1597       return res;
1598     }
1599 #endif
1600     if (modulo<46340){
1601       if (unsig){
1602 	unsigned Alpha=alpha<0?alpha+modulo:alpha;
1603 	unsigned res=0;
1604 	for (;it!=itend;++it){
1605 	  res = (res*Alpha+unsigned(*it))%modulo;
1606 	}
1607 	if (res>(unsigned)(modulo/2))
1608 	  return int(res)-modulo;
1609 	else
1610 	  return int(res);
1611       }
1612       for (;it!=itend;++it){
1613 	res = (res*alpha+*it)%modulo;
1614       }
1615     }
1616     else {
1617       for (;it!=itend;++it){
1618 	res = (res*longlong(alpha)+*it)%modulo;
1619       }
1620     }
1621     register int tmp=res+res;
1622     if (tmp>modulo)
1623       return res-modulo;
1624     if (tmp<=-modulo)
1625       return res+modulo;
1626     return res;
1627   }
1628 
1629   // distribute multiplication
distmult(const vector<T_unsigned<int,hashgcd_U>> & p,const vector<int> & v,vector<T_unsigned<int,hashgcd_U>> & pv,hashgcd_U var,int modulo)1630   static void distmult(const vector< T_unsigned<int,hashgcd_U> > & p,const vector<int> & v,vector< T_unsigned<int,hashgcd_U> > & pv,hashgcd_U var,int modulo){
1631     if (&pv==&p){
1632       if (v.size()==1 && v.front()==1) return;
1633       vector< T_unsigned<int,hashgcd_U> > tmp;
1634       distmult(p,v,tmp,var,modulo);
1635       swap(pv,tmp);
1636       return;
1637     }
1638     pv.clear();
1639     vector< T_unsigned<int,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
1640     vector<int>::const_iterator jtbeg=v.begin(),jtend=v.end(),jt;
1641     int vs=int(jtend-jtbeg),j;
1642     pv.reserve((itend-it)*vs);
1643     if (modulo>=46340){
1644       for (;it!=itend;++it){
1645 	for (jt=jtbeg,j=1;jt!=jtend;++j,++jt){
1646 	  if (*jt)
1647 	    pv.push_back(T_unsigned<int,hashgcd_U>((it->g*longlong(*jt))%modulo,it->u+(vs-j)*var));
1648 	}
1649       }
1650     }
1651     else {
1652       for (;it!=itend;++it){
1653 	for (jt=jtbeg,j=1;jt!=jtend;++j,++jt){
1654 	  if (*jt)
1655 	    pv.push_back(T_unsigned<int,hashgcd_U>((it->g*(*jt))%modulo,it->u+(vs-j)*var));
1656 	}
1657       }
1658     }
1659   }
1660 
1661   // distribute multiplication
distmult(const vector<T_unsigned<vector<int>,hashgcd_U>> & p,const vector<int> & v,vector<T_unsigned<vector<int>,hashgcd_U>> & pv,hashgcd_U var,int modulo)1662   static void distmult(const vector< T_unsigned<vector<int>,hashgcd_U> > & p,const vector<int> & v,vector< T_unsigned<vector<int>,hashgcd_U> > & pv,hashgcd_U var,int modulo){
1663     if (&pv==&p){
1664       vector< T_unsigned<vector<int>,hashgcd_U> > tmp;
1665       distmult(p,v,tmp,var,modulo);
1666       swap(pv,tmp);
1667       return;
1668     }
1669     pv.clear();
1670     vector< T_unsigned<vector<int>,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
1671     vector<int> tmp;
1672     vector<int>::const_iterator jtbeg=v.begin(),jtend=v.end(),jt;
1673     int vs=int(jtend-jtbeg),j;
1674     pv.reserve((itend-it)*vs);
1675     for (;it!=itend;++it){
1676       for (jt=jtbeg,j=1;jt!=jtend;++j,++jt){
1677 	if (*jt){
1678 	  tmp=it->g;
1679 	  mulmod(*jt,tmp,modulo);
1680 	  pv.push_back( T_unsigned<vector<int>,hashgcd_U>(tmp,it->u+(vs-j)*var));
1681 	}
1682       }
1683     }
1684   }
1685 
1686 #if 0
1687   static void distmult(const vector<int> & p,const vector<int> & v,vector< vector<int> > & pv,int modulo){
1688     vector<int>::const_iterator it=p.begin(),itend=p.end(),jt=v.begin(),jtend=v.end();
1689     pv.clear();
1690     pv.insert(pv.end(),(itend-it),vector<int>(0));
1691     if (modulo<=46340){
1692       for (int i=0;it!=itend;++it,++i){
1693 	vector<int> & w = pv[i];
1694 	const int & fact = *it;
1695 	if (fact){
1696 	  w.reserve(v.size());
1697 	  for (jt=v.begin();jt!=jtend;++jt)
1698 	    w.push_back(fact*(*jt) % modulo);
1699 	}
1700       }
1701     }
1702     else {
1703       for (int i=0;it!=itend;++it,++i){
1704 	vector<int> & w = pv[i];
1705 	const int & fact = *it;
1706 	if (fact){
1707 	  w.reserve(v.size());
1708 	  for (jt=v.begin();jt!=jtend;++jt)
1709 	    w.push_back( (longlong(fact)*(*jt)) % modulo);
1710 	}
1711       }
1712     }
1713   }
1714 
1715   void mulmod(const vector<int> & v,int m,vector<int> & w,int modulo){
1716     if (&v==&w){
1717       mulmod(w,m,modulo);
1718       return;
1719     }
1720     vector<int>::const_iterator jt=v.begin(),jtend=v.end();
1721     w.clear();
1722     w.reserve(jtend-jt);
1723     if (modulo>=46340){
1724       for (;jt!=jtend;++jt)
1725 	w.push_back(smod(*jt * longlong(m),modulo));
1726     }
1727     else {
1728       for (;jt!=jtend;++jt)
1729 	w.push_back(smod(*jt * m,modulo));
1730     }
1731   }
1732 #endif
1733 
1734   // if all indices are == return -2
1735   // if all indices corr. to u1 are <= to u2 return 1,
1736   // if all are >= to u2 return 0
1737   // otherwise return -1
compare(hashgcd_U u1,hashgcd_U u2,const vector<hashgcd_U> & vars)1738   int compare(hashgcd_U u1,hashgcd_U u2,const vector<hashgcd_U> & vars){
1739     if (u1==u2)
1740       return -2;
1741     std::vector<hashgcd_U>::const_iterator it=vars.begin(),itend=vars.end();
1742     hashgcd_U r1,r2;
1743     int res=-2;
1744     for (;it!=itend;++it){
1745       r1=u1%(*it);
1746       r2=u2%(*it);
1747       if (r1==r2)
1748 	continue;
1749       if (res==-2){
1750 	res=r1<r2;
1751 	continue;
1752       }
1753       if (r1<r2){
1754 	if (res)
1755 	  continue;
1756 	return -1;
1757       }
1758       else {
1759 	if (!res)
1760 	  continue;
1761 	return -1;
1762       }
1763     }
1764     return res;
1765   }
1766 
1767   // if all indices are == return -2
1768   // if all indices corr. to u1 are <= to u2 return 1,
1769   // if all are >= to u2 return 0
1770   // otherwise return -1
compare(const index_t & u1,const index_t & u2)1771   static int compare(const index_t & u1,const index_t & u2){
1772     if (u1==u2)
1773       return -2;
1774     index_t::const_iterator it=u1.begin(),itend=u1.end(),jt=u2.begin();
1775     int res=-2;
1776     for (;it!=itend;++it,++jt){
1777       if (*it==*jt)
1778 	continue;
1779       if (res==-2){
1780 	res=*it<*jt;
1781 	continue;
1782       }
1783       if (*it<*jt){
1784 	if (res)
1785 	  continue;
1786 	return -1;
1787       }
1788       else {
1789 	if (!res)
1790 	  continue;
1791 	return -1;
1792       }
1793     }
1794     return res;
1795   }
1796 
is_one(const vector<T_unsigned<int,hashgcd_U>> & p)1797   inline bool is_one(const vector< T_unsigned<int,hashgcd_U> > & p){
1798     return p.size()==1 && p.front().g==1 && p.front().u==0;
1799   }
1800 
1801   // Note that smallmult may fail if the degree of a and b * modulo^2
1802   // overflows in a longlong, so keep modulo not too large
smallmult(const vector<int>::const_iterator & ita0,const vector<int>::const_iterator & ita_end,const vector<int>::const_iterator & itb0,const vector<int>::const_iterator & itb_end,vector<int> & new_coord,int modulo)1803   void smallmult(const vector<int>::const_iterator & ita0,const vector<int>::const_iterator & ita_end,const vector<int>::const_iterator & itb0,const vector<int>::const_iterator & itb_end,vector<int> & new_coord,int modulo){
1804     longlong test=longlong(modulo)*std::min(ita_end-ita0,itb_end-itb0);
1805     bool large=test/RAND_MAX>RAND_MAX/modulo;
1806     new_coord.clear();
1807     if (ita0==ita_end || itb0==itb_end) return;
1808     vector<int>::const_iterator ita_begin=ita0,ita=ita0,itb=itb0;
1809     for ( ; ita!=ita_end; ++ita ){
1810       vector<int>::const_iterator ita_cur=ita,itb_cur=itb;
1811       if (large){
1812 	int res=0;
1813 	for (;itb_cur!=itb_end;--ita_cur,++itb_cur) {
1814 	  res = (res + *ita_cur * longlong(*itb_cur))%modulo ;
1815 	  if (ita_cur==ita_begin)
1816 	    break;
1817 	}
1818 	new_coord.push_back(smod(res,modulo));
1819       }
1820       else {
1821 	longlong res=0;
1822 	for (;itb_cur!=itb_end;--ita_cur,++itb_cur) {
1823 	  res += *ita_cur * longlong(*itb_cur) ;
1824 	  if (ita_cur==ita_begin)
1825 	    break;
1826 	}
1827 	new_coord.push_back(smod(res,modulo));
1828       }
1829     }
1830     --ita;
1831     ++itb;
1832     for ( ; itb!=itb_end;++itb){
1833       vector<int>::const_iterator ita_cur=ita,itb_cur=itb;
1834       if (large){
1835 	int res=0;
1836 	for (;;) {
1837 	  res = (res + *ita_cur * longlong(*itb_cur))%modulo ;
1838 	  if (ita_cur==ita_begin)
1839 	    break;
1840 	  --ita_cur;
1841 	  ++itb_cur;
1842 	  if (itb_cur==itb_end)
1843 	    break;
1844 	}
1845 	new_coord.push_back(smod(res,modulo));
1846       }
1847       else {
1848 	longlong res= 0;
1849 	for (;;) {
1850 	  res += *ita_cur * longlong(*itb_cur) ;
1851 	  if (ita_cur==ita_begin)
1852 	    break;
1853 	  --ita_cur;
1854 	  ++itb_cur;
1855 	  if (itb_cur==itb_end)
1856 	    break;
1857 	}
1858 	new_coord.push_back(smod(res,modulo));
1859       }
1860     }
1861   }
1862 
1863 #if 0
1864   static void smallmult1(const vector< T_unsigned<int,hashgcd_U> > & p,const vector< T_unsigned<int,hashgcd_U> > & q,vector< T_unsigned<int,hashgcd_U> > & res,hashgcd_U var,int modulo){
1865     vector<int> p1,q1,r1;
1866     convert(p,var,p1,modulo);
1867     convert(q,var,q1,modulo);
1868     r1.reserve(p1.size()+q1.size()-1);
1869     smallmult(p1.begin(),p1.end(),q1.begin(),q1.end(),r1,modulo);
1870     convert_back(r1,var,res);
1871   }
1872 #endif
1873 
convert(const vector<T_unsigned<int,hashgcd_U>> & p,hashgcd_U var,hashgcd_U var2,vector<vector<int>> & v,int modulo)1874   static void convert(const vector< T_unsigned<int,hashgcd_U> > & p,hashgcd_U var,hashgcd_U var2,vector< vector<int> > & v,int modulo){
1875     if (p.empty()){
1876       v.clear();
1877       return;
1878     }
1879     int dim1=p.front().u/var,dim2;
1880     if (int(v.size())!=dim1+1){
1881       vector< vector<int> > tmp(dim1+1);
1882       swap(tmp,v);
1883     }
1884     vector< T_unsigned<int,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
1885     hashgcd_U u,uend;
1886     int deg,prevdeg=0;
1887     for (;it!=itend;){
1888       u=it->u;
1889       deg=u/var;
1890       if (prevdeg){
1891 	for (--prevdeg;prevdeg>deg;--prevdeg){
1892 	  v[dim1-prevdeg].clear();
1893 	}
1894       }
1895       prevdeg=deg;
1896       uend=deg*var;
1897       dim2=(u-uend)/var2;
1898       vector<int> & vi = v[dim1-deg];
1899       if (int(vi.size())!=dim2+1){
1900 	vector<int> tmp(dim2+1);
1901 	swap(vi,tmp);
1902       }
1903       else
1904 	fill(vi.begin(),vi.end(),0);
1905       if (dim2<itend-it && (it+dim2)->u==uend){
1906 	vector<int>::iterator jt=vi.begin(),jtend=vi.end();
1907 	for (;jt!=jtend;++it,++jt){
1908 #if 1
1909 	  int tmp=it->g;
1910 	  *jt = tmp - (tmp>>31)*modulo;
1911 #else
1912 	  *jt = it->g;
1913 	  if (*jt>=0)
1914 	    continue;
1915 	  *jt += modulo;
1916 #endif
1917 	}
1918 	continue;
1919       }
1920       for (;it!=itend;++it){
1921 	u=it->u;
1922 	if (u<uend)
1923 	  break;
1924 	vi[dim2-(u-uend)/var2]=it->g-(it->g>>31)*modulo;//it->g<0?it->g+modulo:it->g;
1925       }
1926     }
1927     for (--prevdeg;prevdeg>=0;--prevdeg)
1928       v[dim1-prevdeg].clear();
1929   }
1930 
horner_back(const vector<vector<int>> & v,int x,vector<int> & vx,int modulo,int maxdeg=-1,bool unsig=false)1931   static void horner_back(const vector< vector<int> > & v,int x,vector<int> & vx,int modulo,int maxdeg=-1,bool unsig=false){
1932     vector< vector<int> >::const_iterator it=v.begin(),itend=v.end();
1933     if (maxdeg>=0 && maxdeg<itend-it)
1934       it = itend-(maxdeg+1);
1935     vector<int>::iterator jt=vx.begin(),jtend=vx.end();
1936     if (0 && jtend-jt>=itend-it){
1937       for (;it!=itend;++it,++jt){
1938 	*jt=hornermod(*it,x,modulo,unsig);
1939       }
1940       if (jt!=jtend)
1941 	vx.erase(jt,jtend);
1942     }
1943     else {
1944       vx.clear();
1945       vx.reserve(itend-it);
1946       for (;it!=itend;++it){
1947 	vx.push_back(hornermod(*it,x,modulo,unsig));
1948       }
1949     }
1950   }
1951 
horner_front(const vector<vector<int>> & v,int x,vector<int> & vx,int modulo)1952   static void horner_front(const vector< vector<int> > & v,int x,vector<int> & vx,int modulo){
1953     if (!x && !v.empty()){
1954       vx=v.back();
1955       return;
1956     }
1957     vx.clear();
1958     vector< vector<int> >::const_iterator it=v.begin(),itend=v.end();
1959     for (;it!=itend;++it){
1960       mulmod(vx,x,modulo);
1961       addmod(vx,*it,modulo);
1962     }
1963     // trim(vx);
1964   }
1965 
is_equal_modulo(const vector<int> & v,const vector<int> & w,int modulo)1966   static bool is_equal_modulo(const vector<int> & v,const vector<int> & w,int modulo){
1967     vector<int>::const_iterator it=v.begin(),itend=v.end(),jt=w.begin(),jtend=w.end();
1968     if (itend-it!=jtend-jt)
1969       return false;
1970     for (;it!=itend;++jt,++it){
1971       if ((*it-*jt)%modulo)
1972 	return false;
1973     }
1974     return true;
1975   }
1976 
is_p_a_times_b(const vector<int> & p,const vector<int> & a,const vector<int> & b,int modulo,int maxdeg)1977   static bool is_p_a_times_b(const vector<int> & p,const vector<int> & a,const vector<int> & b,int modulo,int maxdeg){
1978     int as=int(a.size()),bs=int(b.size()),ps=int(p.size());
1979     if (ps!=as+bs-1 && ps!=maxdeg+1)
1980       return false;
1981     if (ps<=maxdeg){
1982       vector<int> r;
1983       smallmult(a.begin(),a.end(),b.begin(),b.end(),r,modulo);
1984       return is_equal_modulo(r,p,modulo);
1985     }
1986     longlong test=longlong(modulo)*std::min(maxdeg+1,std::min(as,bs));
1987     bool large=test/RAND_MAX>RAND_MAX/modulo;
1988     int j;
1989     vector<int>::const_iterator it,itbeg=a.begin(),jt,jtend=b.end();
1990     for (int i=0;i<=maxdeg;++i){
1991       // degree i==? p[ps-i-1]= sum_j a[as-1-j]*b[bs-1-i+j]
1992       // starting value for j: 0 or i+1-bs
1993       j=i+1-bs;
1994       if (j<0)
1995 	j=0;
1996       it=itbeg+as-1-j;
1997       jt=b.begin()+bs-1-i+j;
1998       // end value: a.begin() or b.end()
1999       if (large){
2000 	int res = - p[ps-i-1];
2001 	for (;jt!=jtend;--it,++jt){
2002 	  res = (res+(*it)* longlong(*jt))%modulo;
2003 	  if (it==itbeg)
2004 	    break;
2005 	}
2006 	if (res)
2007 	  return false;
2008       }
2009       else {
2010 	longlong res = - p[ps-i-1];
2011 	for (;jt!=jtend;--it,++jt){
2012 	  res += (*it)*longlong(*jt);
2013 	  if (it==itbeg)
2014 	    break;
2015 	}
2016 	if (res%modulo)
2017 	  return false;
2018       }
2019     }
2020     return true;
2021   }
2022 
is_p_a_times_b(const vector<T_unsigned<int,hashgcd_U>> & p,const vector<T_unsigned<int,hashgcd_U>> & a,const vector<T_unsigned<int,hashgcd_U>> & b,const std::vector<hashgcd_U> & vars,int modulo,int maxtotaldeg)2023   static bool is_p_a_times_b(const vector< T_unsigned<int,hashgcd_U> > & p,const vector< T_unsigned<int,hashgcd_U> > & a,const vector< T_unsigned<int,hashgcd_U> > & b,const std::vector<hashgcd_U> & vars,int modulo,int maxtotaldeg){
2024     if (a.empty() || b.empty())
2025       return p.empty();
2026     if (p.empty())
2027       return false;
2028     int dim=int(vars.size())-1;
2029     if (dim<=0)
2030       return false; // setdimerr();
2031     // double as=a.size(),bs=b.size();
2032     double ps=double(p.size());
2033     hashgcd_U var2=vars[dim-1];
2034     if (dim==1){
2035       // ? dense vector<int> multiplication or sparse mult ?
2036       unsigned adeg=a.front().u/var2,bdeg=b.front().u/var2,pdeg=p.front().u/var2;
2037       if (pdeg!=adeg+bdeg && int(pdeg)!=maxtotaldeg)
2038 	return false;
2039       // double timesparse=as*bs*std::log(ps);
2040       // double timedense=(adeg+1)*(bdeg+1);
2041       if (true
2042 	  // timedense<timesparse
2043 	  ){
2044 	vector<int> p1,a1,b1,r1;
2045 	convert(a,var2,a1,modulo);
2046 	convert(b,var2,b1,modulo);
2047 	convert(p,var2,p1,modulo);
2048 	return is_p_a_times_b(p1,a1,b1,modulo,maxtotaldeg);
2049       }
2050       // FIXME take maxdeg in account
2051       vector< T_unsigned<int,hashgcd_U> > r;
2052       smallmult(a,b,r,modulo,size_t(ps+1));
2053       smallsub(r,p,r,modulo);
2054       return r.empty();
2055     }
2056     hashgcd_U var=vars[dim-2];
2057     int shift_var=find_shift(var),shift_var2=find_shift(var2);
2058     unsigned adeg=degree_xn(a,shift_var,shift_var2),bdeg=degree_xn(b,shift_var,shift_var2),pdeg=degree_xn(p,shift_var,shift_var2);
2059     int ntests=std::min(int(pdeg),maxtotaldeg);
2060     if (pdeg!=adeg+bdeg && int(pdeg)!=maxtotaldeg)
2061       return false;
2062     // multiplication requires as*bs*ln(ps) operations
2063     // alternative is checking pdeg+1 values of x=xn
2064     // time for 1 check: ps+as+bs (horner)+ dim^2*as/adeg*bs/bdeg*ln(ps)
2065     // double timemult=3*as*bs*std::log(ps);
2066     // double timeeval=(ntests+1)*(ps+as+bs+dim*dim*as/adeg*bs/bdeg*std::log(ps));
2067     if (false
2068 	// timemult<timeeval
2069 	){
2070       vector< T_unsigned<int,hashgcd_U> > r;
2071       smallmult(a,b,r,modulo,size_t(ps));
2072       smallsub(r,p,r,modulo);
2073       // FIXME take maxdeg in account
2074       return r.empty();
2075     }
2076     if (dim==2){
2077       vector< vector<int> > pv,av,bv;
2078       vector<int> pi,ai,bi,ri;
2079       convert(p,var,var2,pv,modulo);
2080       convert(a,var,var2,av,modulo);
2081       convert(b,var,var2,bv,modulo);
2082       for (int i=0;i<=ntests;++i){
2083 	int alpha=i%2?-(i+1)/2:i/2;
2084 	horner_back(pv,alpha,pi,modulo,maxtotaldeg,true);
2085 	horner_back(av,alpha,ai,modulo,maxtotaldeg,true);
2086 	horner_back(bv,alpha,bi,modulo,maxtotaldeg,true);
2087 	if (!is_p_a_times_b(pi,ai,bi,modulo,maxtotaldeg))
2088 	  return false;
2089 	--maxtotaldeg;
2090       }
2091       return true;
2092     }
2093     vector< T_unsigned<int,hashgcd_U> > pi,ai,bi;
2094     std::vector<hashgcd_U> vars_truncated(vars);
2095     vars_truncated.pop_back();
2096     for (int i=0;i<=ntests;++i){
2097       if (!horner(p,i,vars_truncated,pi,modulo,maxtotaldeg) ||
2098 	  !horner(a,i,vars_truncated,ai,modulo,maxtotaldeg) ||
2099 	  !horner(b,i,vars_truncated,bi,modulo,maxtotaldeg))
2100 	return false;
2101       if (!is_p_a_times_b(pi,ai,bi,vars_truncated,modulo,maxtotaldeg))
2102 	return false;
2103       --maxtotaldeg;
2104     }
2105     return true;
2106   }
2107 
2108   /*
2109   template<class T>
2110   void divided_differences(const vector<int> & x,vector< vector< T_unsigned<T,hashgcd_U> > > & res,int modulo){
2111     int s=x.size();
2112     int fact;
2113     for (int k=1;k<s;++k){
2114       for (int j=s-1;j>=k;--j){
2115 	smallsub(res[j],res[j-1],res[j],modulo);
2116 	fact=invmod(x[j]-x[j-k],modulo);
2117 	if (fact!=1)
2118 	  smallmult(fact,res[j],res[j],modulo);
2119       }
2120     }
2121   }
2122   */
2123 
2124   template<class T>
divided_differences(const vector<int> & x,vector<vector<T_unsigned<T,hashgcd_U>>> & res,int modulo)2125   static void divided_differences(const vector<int> & x,vector< vector< T_unsigned<T,hashgcd_U> > > & res,int modulo){
2126     int s=int(x.size());
2127     int fact;
2128     vector< T_unsigned<T,hashgcd_U> > tmp;
2129     for (int k=1;k<s;++k){
2130       for (int j=s-1;j>=k;--j){
2131 	smallsub(res[j],res[j-1],tmp,modulo);
2132 	swap(tmp,res[j]);
2133 	fact=invmod(x[j]-x[j-k],modulo);
2134 	if (fact!=1)
2135 	  smallmult(fact,res[j],res[j],modulo);
2136       }
2137     }
2138   }
2139 
2140   // Lagrange interpolation at x/y (with 2 temporary polynomials)
2141   template<class T>
interpolate(const vector<int> & x,vector<vector<T_unsigned<T,hashgcd_U>>> & diff,vector<T_unsigned<T,hashgcd_U>> & res,hashgcd_U varx,int modulo,vector<T_unsigned<T,hashgcd_U>> & tmp,vector<T_unsigned<T,hashgcd_U>> & tmp2)2142   static void interpolate(const vector<int> & x,vector< vector< T_unsigned<T,hashgcd_U> > > & diff,vector< T_unsigned<T,hashgcd_U> > & res,hashgcd_U varx,int modulo,vector< T_unsigned<T,hashgcd_U> > & tmp,vector< T_unsigned<T,hashgcd_U> > & tmp2){
2143     divided_differences(x,diff,modulo);
2144     int s=int(diff.size());
2145     vector<int> interp(1,1);
2146     res=diff.front();
2147     int alpha;
2148     /* estimate size required to avoid reallocations */
2149     size_t S=diff[s-1].size()*(1ULL>>((s+1)/2));
2150     tmp.reserve(S); tmp2.reserve(S); res.reserve(S);
2151     for (int j=1;j<s;++j){
2152       alpha=x[j-1];
2153       interp.push_back(smod(-longlong(alpha)*interp[j-1],modulo));
2154       for (int i=j-1;i>0;--i){
2155 	interp[i]=smod(-longlong(alpha)*interp[i-1]+interp[i],modulo);
2156       }
2157       distmult(diff[j],interp,tmp,varx,modulo);
2158       smalladd(res,tmp,tmp2,modulo);
2159       swap(tmp2,res);
2160     }
2161     if (0) CERR << res.size() << " " << res.capacity() << '\n';
2162     /*
2163     res=diff[s-1];
2164     vector< T_unsigned<int,hashgcd_U> > res_shift,res_times;
2165     for (int i=s-2;i>=0;--i){
2166       // res = res*(x-x[i])+diff[i];
2167       smallshift(res,varx,res_shift);
2168       smallmult(-x[i],res,res_times,modulo);
2169       smalladd(res_times,diff[i],res_times,modulo);
2170       smalladd(res_shift,res_times,res,modulo);
2171     }
2172     */
2173   }
2174 
2175   // Lagrange interpolation at x/y
2176   template<class T>
interpolate(const vector<int> & x,vector<vector<T_unsigned<T,hashgcd_U>>> & diff,vector<T_unsigned<T,hashgcd_U>> & res,hashgcd_U varx,int modulo)2177   static void interpolate(const vector<int> & x,vector< vector< T_unsigned<T,hashgcd_U> > > & diff,vector< T_unsigned<T,hashgcd_U> > & res,hashgcd_U varx,int modulo){
2178     vector< T_unsigned<T,hashgcd_U> > tmp,tmp2;
2179     interpolate(x,diff,res,varx,modulo,tmp,tmp2);
2180   }
2181 
divided_differences_dim2(const vector<int> & x,vector<vector<int>> & res,int modulo)2182   static void divided_differences_dim2(const vector<int> & x,vector< vector<int> > & res,int modulo){
2183     int s=int(x.size());
2184     int fact;
2185     for (int k=1;k<s;++k){
2186       for (int j=s-1;j>=k;--j){
2187 	fact=invmod(x[j]-x[j-k],modulo);
2188 	mulsubmod(fact,res[j],res[j-1],modulo);
2189 	/*
2190 	submod(res[j],res[j-1],modulo);
2191 	if (fact!=1)
2192 	  mulmod(res[j],fact,modulo);
2193 	*/
2194       }
2195     }
2196   }
2197 
2198   // Lagrange interpolation at x/y
interpolate_dim2(const vector<int> & x,vector<vector<int>> & diff,vector<vector<int>> & res,int modulo)2199   static void interpolate_dim2(const vector<int> & x,vector< vector<int> > & diff,vector< vector<int> > & res,int modulo){
2200     assert(x.size()<=diff.size());
2201     divided_differences_dim2(x,diff,modulo);
2202     // CERR << "end diff div " << CLOCK() << '\n';
2203     int s=int(x.size()),alpha;
2204     int ysize=0,cur;
2205     for (int i=0;i<s;++i){
2206       if ( (cur=int(diff[i].size())) >ysize )
2207 	ysize=cur;
2208     }
2209     res.resize(ysize);
2210     for (int i=0;i<ysize;++i)
2211       res[i].reserve(s);
2212     for (int i=ysize-1;i>=0;--i){
2213       vector<int> & curx = res[ysize-i-1];
2214       curx.clear();
2215       vector<int> & cury = diff[s-1];
2216       if ( (cur=int(cury.size())) >i)
2217 	curx.push_back(cury[cur-1-i]);
2218       for (int j=s-2;;--j){
2219 	// multiply curx by (x-x[j])
2220 	alpha=-x[j];
2221 	if (!curx.empty()){
2222 	  curx.push_back( (longlong(alpha)*curx.back()) % modulo );
2223 	  vector<int>::iterator it=curx.end()-2,itbeg=curx.begin();
2224 	  for (;it!=itbeg;){
2225 	    int & curxk=*it;
2226 	    --it;
2227 	    type_operator_plus_times_reduce(alpha,*it,curxk,modulo);
2228 	  }
2229 	}
2230 	// add diff[j]
2231 	vector<int> & cury = diff[j];
2232 	if ( (cur=int(cury.size())) >i){
2233 	  if (curx.empty())
2234 	    curx.push_back(cury[cur-1-i]);
2235 	  else
2236 	    curx.back() = (curx.back() + cury[cur-1-i])%modulo;
2237 	}
2238 	if (!j)
2239 	  break;
2240       }
2241       if (0) CERR << curx.size() << " " << curx.capacity() << '\n';
2242     }
2243     /*
2244     vector<int> interp(1,1);
2245     distmult(diff[0],interp,res,modulo);
2246     vector< vector<int> >::iterator it=res.begin(),itend=res.end();
2247     for (;it!=itend;++it)
2248       it->reserve(s);
2249     vector< vector<int> > tmp;
2250     for (int j=1;j<s;++j){
2251       alpha=x[j-1];
2252       interp.push_back(smod(-longlong(alpha)*interp[j-1],modulo));
2253       for (int i=j-1;i>0;--i){
2254 	interp[i]=smod(-longlong(alpha)*interp[i-1]+interp[i],modulo);
2255       }
2256       distmult(diff[j],interp,tmp,modulo);
2257       addmod(res,tmp,modulo);
2258     }
2259     */
2260     // unsigne res
2261     s=int(res.size());
2262     for (int j=0;j<s;++j){
2263       vector<int> & cur=res[j];
2264       vector<int>::iterator it=cur.begin(),itend=cur.end();
2265       for (;it!=itend;++it){
2266 #if 0
2267 	if (*it<0)
2268 	  *it += modulo;
2269 #else
2270 	*it -= (*it>>31)*modulo;
2271 #endif
2272       }
2273     }
2274   }
2275 
interpolate_dim2_convert(const vector<int> & x,vector<vector<int>> & y,vector<T_unsigned<int,hashgcd_U>> & res,int varxn,int var2,int modulo)2276   static void interpolate_dim2_convert(const vector<int> & x,vector< vector<int> > & y,vector< T_unsigned<int,hashgcd_U> > & res,int varxn,int var2,int modulo){
2277     vector< vector<int> > tmp;
2278     interpolate_dim2(x,y,tmp,modulo);
2279     convert_back(tmp,varxn,var2,res);
2280   }
2281 
2282   template<class T>
2283   struct gcd_call_param {
2284     vector<T> * Delta ;
2285     vector<T> * lcoeffp ;
2286     vector<T> * lcoeffq ;
2287     vector<int> * alphav;
2288     vector< vector<T> > * pv ;
2289     vector< vector<T> > * qv ;
2290     vector< vector<T> > * dv ;
2291     vector< vector<T> > * dpv ;
2292     vector< vector<T> > * dim2gcdv ;
2293     vector< vector<T> > * dim2pcofactorv ;
2294     vector< vector<T> > * dim2qcofactorv ;
2295     vector<T> * dim2palphaptr;
2296     vector<T> * dim2qalphaptr;
2297     const vector< T_unsigned<T,hashgcd_U> > * p ;
2298     const vector< T_unsigned<T,hashgcd_U> > * q ;
2299     vector< vector< T_unsigned<T,hashgcd_U> > > * gcdv ;
2300     vector< vector< T_unsigned<T,hashgcd_U> > > * pcofactorv ;
2301     vector< vector< T_unsigned<T,hashgcd_U> > > * qcofactorv ;
2302     index_t * pdeg ;
2303     index_t * qdeg ;
2304     const vector<hashgcd_U> * vars ;
2305     vector<hashgcd_U> * vars_truncated ;
2306     //index_t * shift_vars ;
2307     index_t * shift_vars_truncated ;
2308     bool compute_cof ;
2309     bool compute_qcofactor ;
2310     bool dim2;
2311     const vector<int> * pminptr;
2312     int modulo ;
2313     int vpos ;
2314     int nthreads ;
2315     int ext_gcd_ok ; // used for gcd over algebraic extension of Q
2316   };
2317 
2318   static bool mod_gcd(const vector< T_unsigned<int,hashgcd_U> > & p_orig,const vector< T_unsigned<int,hashgcd_U> > & q_orig,int modulo,vector< T_unsigned<int,hashgcd_U> > & d, vector< T_unsigned<int,hashgcd_U> > & pcofactor, vector< T_unsigned<int,hashgcd_U> > & qcofactor,const std::vector<hashgcd_U> & vars, bool compute_pcofactor,bool compute_qcofactor,bool & divtest,vector< vector<int> > & pv,vector< vector<int> > & qv,vector< vector<int> > & dv,vector< vector<int> > & dpv,vector< vector<int> > & dim2gcdv,vector< vector<int> > & dim2pcofactorv,vector< vector<int> > & dim2qcofactorv,int nthreads);
2319 
2320 #ifndef NO_TEMPLATE_MULTGCD
do_recursive_gcd_call(void * ptr_)2321   static void * do_recursive_gcd_call(void * ptr_){
2322 #ifdef TIMEOUT
2323     control_c();
2324 #endif
2325     if (ctrl_c || interrupted)
2326       return 0;
2327     gcd_call_param<int> * ptr = (gcd_call_param<int> *) ptr_;
2328     vector<int> & Delta = *ptr->Delta;
2329     vector<int> & lcoeffp = *ptr->lcoeffp;
2330     vector<int> & lcoeffq = *ptr->lcoeffq;
2331     vector<int> & alphav = * ptr->alphav;
2332     vector< vector<int> > & pv = *ptr->pv;
2333     vector< vector<int> > & qv = *ptr->qv;
2334     vector< vector<int> > & dv = *ptr->dv;
2335     vector< vector<int> > & dpv = *ptr->dpv;
2336     vector<int> dim2palpha_nthreads;
2337     vector<int> dim2qalpha_nthreads;
2338     vector<int> * dim2palphaptr=ptr->dim2palphaptr;
2339     if (!dim2palphaptr)
2340       dim2palphaptr=&dim2palpha_nthreads;
2341     vector<int> * dim2qalphaptr=ptr->dim2qalphaptr;
2342     if (!dim2qalphaptr)
2343       dim2qalphaptr=&dim2qalpha_nthreads;
2344     vector< vector<int> > & dim2gcdv = *ptr->dim2gcdv;
2345     vector< vector<int> > & dim2pcofactorv = *ptr->dim2pcofactorv;
2346     vector< vector<int> > & dim2qcofactorv = *ptr->dim2qcofactorv;
2347     const vector< T_unsigned<int,hashgcd_U> > & p = * ptr->p;
2348     const vector< T_unsigned<int,hashgcd_U> > & q = * ptr->q;
2349     vector< vector< T_unsigned<int,hashgcd_U> > > & gcdv = * ptr->gcdv;
2350     vector< vector< T_unsigned<int,hashgcd_U> > > & pcofactorv = * ptr->pcofactorv;
2351     vector< vector< T_unsigned<int,hashgcd_U> > > & qcofactorv = * ptr->qcofactorv;
2352     index_t & pdeg = * ptr->pdeg;
2353     index_t & qdeg = * ptr->qdeg;
2354     vector< T_unsigned<int,hashgcd_U> > palpha,qalpha;
2355     index_t pdegalpha,qdegalpha;
2356     int vpos=ptr->vpos;
2357     int alpha1 = alphav[vpos];
2358     int modulo = ptr->modulo;
2359     const vector<hashgcd_U> & vars = * ptr->vars;
2360     vector<hashgcd_U> & vars_truncated = * ptr->vars_truncated;
2361     // index_t & shift_vars = *ptr->shift_vars;
2362     index_t & shift_vars_truncated = *ptr->shift_vars_truncated;
2363     bool compute_cof = ptr->compute_cof;
2364     bool compute_qcofactor = ptr->compute_qcofactor;
2365     bool dim2 = ptr->dim2;
2366     int nthreads = ptr->nthreads;
2367     // Eval p and q at xn=alpha
2368     if (dim2){
2369       horner_back(pv,alpha1,*dim2palphaptr,modulo,-1,true);
2370       if ( int(dim2palphaptr->size())-1 != pdeg.front())
2371 	return 0;
2372       // convert(dim2palpha,varxn,palpha);
2373       horner_back(qv,alpha1,*dim2qalphaptr,modulo,-1,true);
2374       if ( int(dim2qalphaptr->size())-1 != qdeg.front())
2375 	return 0;
2376       // convert(dim2qalpha,varxn,qalpha);
2377     }
2378     else {
2379       if (!horner(p,alpha1,vars,palpha,modulo,-1))
2380 	return 0;
2381       degree(palpha,shift_vars_truncated,pdegalpha);
2382       pdegalpha.push_back(pdeg.back());
2383       if (pdegalpha!=pdeg)
2384 	return 0;
2385       if (!horner(q,alpha1,vars,qalpha,modulo,-1))
2386 	return 0;
2387       degree(qalpha,shift_vars_truncated,qdegalpha);
2388       qdegalpha.push_back(qdeg.back());
2389       if (qdegalpha!=qdeg)
2390 	return 0;
2391     }
2392     if (dim2){
2393       gcdsmallmodpoly(*dim2palphaptr,*dim2qalphaptr,modulo,dim2gcdv[vpos],compute_cof?&dim2pcofactorv[vpos]:0,(compute_cof && compute_qcofactor)?&dim2qcofactorv[vpos]:0);
2394       mulmod(dim2gcdv[vpos],smod(hornermod(Delta,alpha1,modulo)*longlong(invmod(dim2gcdv[vpos].front(),modulo)),modulo),modulo);
2395       if (compute_cof){
2396 	mulmod(dim2pcofactorv[vpos],smod(hornermod(lcoeffp,alpha1,modulo)*longlong(invmod(dim2pcofactorv[vpos].front(),modulo)),modulo),modulo);
2397 	if (compute_qcofactor){
2398 	  mulmod(dim2qcofactorv[vpos],smod(hornermod(lcoeffq,alpha1,modulo)*longlong(invmod(dim2qcofactorv[vpos].front(),modulo)),modulo),modulo);
2399 	}
2400       }
2401     }
2402     else {
2403       vector< T_unsigned<int,hashgcd_U> > & g=gcdv[vpos];
2404       vector< T_unsigned<int,hashgcd_U> > & gp=pcofactorv[vpos];
2405       vector< T_unsigned<int,hashgcd_U> > & gq=qcofactorv[vpos];
2406       bool tmptestdiv;
2407       if (
2408 #ifdef POCKETCAS
2409 	  true
2410 #else
2411 	  &pv && &qv
2412 #endif
2413 	  ){
2414 	if (!mod_gcd(palpha,qalpha,modulo,g,gp,gq,vars_truncated,compute_cof,compute_qcofactor,tmptestdiv,pv,qv,dv,dpv,dim2gcdv,dim2pcofactorv,dim2qcofactorv,nthreads)){
2415 	  g.clear();
2416 	  return 0;
2417 	}
2418       }
2419       else {
2420 	vector< vector<int> > pv1,qv1,dv1,dpv1,dim2gcdv1,dim2pcofactorv1,dim2qcofactorv1;
2421 	if (!mod_gcd(palpha,qalpha,modulo,g,gp,gq,vars_truncated,compute_cof,compute_qcofactor,tmptestdiv,pv1,qv1,dv1,dpv1,dim2gcdv1,dim2pcofactorv1,dim2qcofactorv1,nthreads)){
2422 	  g.clear();
2423 	  return 0;
2424 	}
2425       }
2426       smallmult(smod(hornermod(Delta,alpha1,modulo)*longlong(invmod(g.front().g,modulo)),modulo),g,g,modulo);
2427       if (compute_cof){
2428 	// adjust gp lcoeff
2429 	smallmult(smod(hornermod(lcoeffp,alpha1,modulo)*longlong(invmod(gp.front().g,modulo)),modulo),gp,gp,modulo);
2430 	if (compute_qcofactor){
2431 	  // adjust gq cofactor
2432 	  smallmult(smod(hornermod(lcoeffq,alpha1,modulo)*longlong(invmod(gq.front().g,modulo)),modulo),gq,gq,modulo);
2433 	}
2434       }
2435     }
2436     return ptr;
2437   }
2438 #endif //NO_TEMPLATE_MULTGCD
2439 
2440 #ifdef HAVE_LIBPTHREAD
2441   pthread_mutex_t gcd_mutex=PTHREAD_MUTEX_INITIALIZER;
2442 #endif
2443 
gcd_mutex_lock()2444   static void gcd_mutex_lock(){
2445 #ifdef HAVE_LIBPTHREAD
2446     pthread_mutex_lock(&gcd_mutex);
2447 #endif
2448   }
2449 
gcd_mutex_unlock()2450   static void gcd_mutex_unlock(){
2451 #ifdef HAVE_LIBPTHREAD
2452     pthread_mutex_unlock(&gcd_mutex);
2453 #endif
2454   }
2455 
2456   // Modular gcd in "internal form"
mod_gcd(const vector<T_unsigned<int,hashgcd_U>> & p_orig,const vector<T_unsigned<int,hashgcd_U>> & q_orig,int modulo,vector<T_unsigned<int,hashgcd_U>> & d,vector<T_unsigned<int,hashgcd_U>> & pcofactor,vector<T_unsigned<int,hashgcd_U>> & qcofactor,const std::vector<hashgcd_U> & vars,bool compute_pcofactor,bool compute_qcofactor,bool & divtest,vector<vector<int>> & pv,vector<vector<int>> & qv,vector<vector<int>> & dv,vector<vector<int>> & dpv,vector<vector<int>> & dim2gcdv,vector<vector<int>> & dim2pcofactorv,vector<vector<int>> & dim2qcofactorv,int nthreads)2457   static bool mod_gcd(const vector< T_unsigned<int,hashgcd_U> > & p_orig,const vector< T_unsigned<int,hashgcd_U> > & q_orig,int modulo,vector< T_unsigned<int,hashgcd_U> > & d, vector< T_unsigned<int,hashgcd_U> > & pcofactor, vector< T_unsigned<int,hashgcd_U> > & qcofactor,const std::vector<hashgcd_U> & vars, bool compute_pcofactor,bool compute_qcofactor,bool & divtest,vector< vector<int> > & pv,vector< vector<int> > & qv,vector< vector<int> > & dv,vector< vector<int> > & dpv,vector< vector<int> > & dim2gcdv,vector< vector<int> > & dim2pcofactorv,vector< vector<int> > & dim2qcofactorv,int nthreads){
2458 #ifdef NO_TEMPLATE_MULTGCD
2459     return false;
2460 #else
2461     divtest=true;
2462     if (p_orig.empty() || is_one(q_orig) ){
2463       d=q_orig;
2464       if (compute_pcofactor)
2465 	pcofactor=p_orig;
2466       if (compute_qcofactor){
2467 	if (p_orig.empty()){
2468 	  qcofactor.clear();
2469 	  qcofactor.push_back(T_unsigned<int,hashgcd_U>(1,0));
2470 	}
2471 	else
2472 	  qcofactor=q_orig;
2473       }
2474       return true;
2475     }
2476     if (q_orig.empty() || is_one(p_orig) ){
2477       d=p_orig;
2478       if (compute_qcofactor)
2479 	qcofactor=q_orig;
2480       if (compute_pcofactor){
2481 	if (q_orig.empty()){
2482 	  pcofactor.clear();
2483 	  pcofactor.push_back(T_unsigned<int,hashgcd_U>(1,0));
2484 	}
2485 	else
2486 	  pcofactor=p_orig;
2487       }
2488       return true;
2489     }
2490     if (&p_orig==&d || &q_orig==&d){
2491       vector< T_unsigned<int,hashgcd_U> > res;
2492       bool b=mod_gcd(p_orig,q_orig,modulo,res,pcofactor,qcofactor,vars,compute_pcofactor,compute_qcofactor,divtest,qv,pv,dv,dpv,dim2gcdv,dim2qcofactorv,dim2pcofactorv,nthreads);
2493       swap(res,d);
2494       return b;
2495     }
2496     d.clear();
2497     // Check dim, if 1 ->
2498     int dim=int(vars.size());
2499     if (dim==1){
2500       hashgcd_U var=vars.front();
2501       vector<int> pv,qv,dv,pvcof,qvcof;
2502       convert(p_orig,var,pv,modulo);
2503       convert(q_orig,var,qv,modulo);
2504       gcdsmallmodpoly(pv,qv,modulo,dv,compute_pcofactor?&pvcof:0,compute_qcofactor?&qvcof:0);
2505       convert_back(dv,var,d);
2506       if (compute_pcofactor){
2507 	convert_back(pvcof,var,pcofactor);
2508       }
2509       if (compute_qcofactor){
2510 	convert_back(qvcof,var,qcofactor);
2511       }
2512       return true;
2513     }
2514     // variable decl and memory allocation
2515     vector<int> pb,qb,db,b(dim-1),bnext(dim-1);
2516     pb.reserve(64); qb.reserve(64); db.reserve(64);
2517     index_t pdeg(dim),qdeg(dim),gdeg(dim-1),delta(dim);
2518     index_t vzero,vzerotmp; // SPMOD: coeff of vzero correspond to zero or non zero in gcd
2519     int nzero=1; // Number of zero coeffs in gcd
2520     vector< T_unsigned<int,hashgcd_U> > pcont,qcont,dcont,tmp;
2521     pcont.reserve(1); qcont.reserve(1);
2522     vector<int> pcontxn(16),qcontxn(16),dcontxn(16),pcofcontxn(16),qcofcontxn(16);
2523     std::vector<hashgcd_U> vars_truncated(vars);
2524     vars_truncated.pop_back();
2525     hashgcd_U varxn=vars_truncated.back(),var2=vars.back();
2526     vector<int> lcoeffp(64),lcoeffq(64),Delta(64);
2527     lcoeffp.reserve( (p_orig.begin()->u%varxn)/var2);
2528     lcoeffq.reserve( (q_orig.begin()->u%varxn)/var2);
2529     vector<int> alphav,dim2palpha,tmpcont(16);
2530     alphav.reserve(64); dim2palpha.reserve(64);
2531     vector<int> dim2palpha_nthreads,dim2qalpha_nthreads;
2532     dim2palpha_nthreads.reserve(64); dim2qalpha_nthreads.reserve(64);
2533     index_t shift_vars;
2534     if (!find_shift(vars,shift_vars))
2535       return false; // setsizeerr();
2536     short int shiftxn=shift_vars[shift_vars.size()-2],shift2=shift_vars.back();
2537     // Make p and q primitive as polynomials in x1,...,xn-1
2538     // with coeff polynomial in xn
2539     if (debug_infolevel>20-dim)
2540       CERR << "gcdmod threads " << nthreads << " content begin " << "dim " << dim << " " << CLOCK() << '\n';
2541     vector< T_unsigned<int,hashgcd_U> > p_pp,q_pp;
2542     int rp=pp_mod_last(p_orig,0,modulo,varxn,var2,pcontxn,p_pp);
2543     int rq=pp_mod_last(q_orig,0,modulo,varxn,var2,qcontxn,q_pp);
2544     const vector< T_unsigned<int,hashgcd_U> > * p_ptr=rp==2?&p_pp:&p_orig;
2545     const vector< T_unsigned<int,hashgcd_U> > * q_ptr=rq==2?&q_pp:&q_orig;
2546     gcdsmallmodpoly(pcontxn,qcontxn,modulo,dcontxn,compute_pcofactor?&pcofcontxn:0,compute_qcofactor?&qcofcontxn:0);
2547     if (debug_infolevel>20-dim)
2548       CERR << "gcdmod content in " << "dim " << dim << " " << CLOCK() << '\n';
2549     // Make p and q primitive as polynomial in xn with coeff in x1...xn-1
2550     if (dim==2){
2551       convert(*p_ptr,varxn,var2,pv,modulo);
2552       if (is_front_primitive(pv,modulo)){
2553 	pcont.push_back(T_unsigned<int,hashgcd_U>(1,0));
2554 	rp=2;
2555       }
2556       else {
2557 	rp=pp_mod(*p_ptr,0,modulo,vars,pcont,nthreads,p_pp);
2558 	if (rp==2){ // non trivial content
2559 	  p_ptr=&p_pp;
2560 	  convert(p_pp,varxn,var2,pv,modulo);
2561 	}
2562       }
2563       convert(*q_ptr,varxn,var2,qv,modulo);
2564       if (is_front_primitive(qv,modulo)){
2565 	qcont.push_back(T_unsigned<int,hashgcd_U>(1,0));
2566 	rq=2;
2567       }
2568       else {
2569 	rq=pp_mod(*q_ptr,0,modulo,vars,qcont,nthreads,q_pp);
2570 	if (rq==2){ // non trivial content
2571 	  convert(q_pp,varxn,var2,qv,modulo);
2572 	  q_ptr=&q_pp;
2573 	}
2574       }
2575     }
2576     else {
2577       rp=pp_mod(*p_ptr,0,modulo,vars,pcont,nthreads,p_pp);
2578       if (rp==2)
2579 	p_ptr=&p_pp;
2580       rq=pp_mod(*q_ptr,0,modulo,vars,qcont,nthreads,q_pp);
2581       if (rq==2)
2582 	q_ptr=&q_pp;
2583     }
2584     int pxndeg=degree_xn(*p_ptr,shiftxn,shift2),qxndeg=degree_xn(*q_ptr,shiftxn,shift2),gcddeg=0,minpqxndeg=giacmin(pxndeg,qxndeg);
2585     bool pqswap=qxndeg<pxndeg; // swap p and q ?
2586     if (pqswap){
2587       swap(p_ptr,q_ptr);
2588       swap(pcont,qcont);
2589       swap(pcofactor,qcofactor);
2590       swap(pxndeg,qxndeg);
2591       swap(pv,qv);
2592       swap(dim2pcofactorv,dim2qcofactorv);
2593 #ifdef BESTA_OS
2594       bool tmpbool=compute_pcofactor;
2595       compute_pcofactor=compute_qcofactor;
2596       compute_qcofactor=tmpbool;
2597       // BESTA DOES NOT LIKE THE FOLLOWING LINE OF CODE
2598 #else
2599       swap(compute_pcofactor,compute_qcofactor);
2600 #endif
2601     }
2602     const vector< T_unsigned<int,hashgcd_U> > & p=*p_ptr;
2603     const vector< T_unsigned<int,hashgcd_U> > & q=*q_ptr;
2604     mod_gcd(pcont,qcont,modulo,dcont,pcofactor,qcofactor,vars_truncated,compute_pcofactor,compute_qcofactor,nthreads); // don't use pv and qv here!
2605     // multiply pcofactor and qcofactor by the initial contents dep. on xn
2606     if (debug_infolevel>20-dim)
2607       CERR << "gcdmod content end " << "dim " << dim << " " << CLOCK() << '\n';
2608     if (compute_pcofactor){
2609       convert_back(pcofcontxn,vars.back(),tmp);
2610       smallmult(pcofactor,tmp,pcofactor,modulo,0);
2611     }
2612     if (compute_qcofactor){
2613       convert_back(qcofcontxn,vars.back(),tmp);
2614       smallmult(qcofactor,tmp,qcofactor,modulo,0);
2615     }
2616     distmult(dcont,dcontxn,dcont,var2,modulo);
2617     // ready for gcd computation by interpolation with respect to xn
2618     // first find degree of gcd with respect to xn
2619     for (int essai=0;essai<2;){
2620       if (debug_infolevel>20-dim)
2621 	CERR << "gcdmod degree? " << essai << " dim " << dim << " " << CLOCK() << '\n';
2622       if (dim==2){
2623 	horner_front(pv,b.front(),pb,modulo);
2624 	horner_front(qv,b.front(),qb,modulo);
2625       }
2626       else {
2627 	if (!horner(p,b,vars,pb,modulo) ||
2628 	    !horner(q,b,vars,qb,modulo))
2629 	  return false;
2630       }
2631       for (;;){
2632 	for (int i=0;i<dim-1;++i)
2633 	  bnext[i]=std_rand() % modulo;
2634 	if (!(bnext==b)){ b=bnext; break; }
2635       }
2636       if (int(pb.size())!=pxndeg+1 || int(qb.size())!=qxndeg+1)
2637 	continue;
2638       gcdsmallmodpoly(pb,qb,modulo,db);
2639       int dbdeg=int(db.size())-1;
2640       if (!dbdeg){
2641 	d=dcont;
2642 	if (compute_pcofactor){
2643 	  smallmult(pcofactor,p,pcofactor,modulo,0);
2644 	  smallmult(smod(longlong(p_orig.front().g)*invmod(pcofactor.front().g,modulo),modulo),pcofactor,pcofactor,modulo);
2645 	}
2646 	if (compute_qcofactor){
2647 	  smallmult(qcofactor,q,qcofactor,modulo,0);
2648 	  smallmult(smod(longlong(q_orig.front().g)*invmod(qcofactor.front().g,modulo),modulo),qcofactor,qcofactor,modulo);
2649 	}
2650 	return true;
2651       }
2652       if (!essai){ // 1st gcd test
2653 	gcddeg=dbdeg;
2654 	if (dim!=2) nzero=find_nonzero(db,vzero);
2655 	++essai;
2656 	continue;
2657       }
2658       // 2nd try
2659       if (dbdeg<gcddeg){ // 1st try was unlucky, restart 1st try
2660 	gcddeg=dbdeg;
2661 	if (dim!=2) nzero=find_nonzero(db,vzero);
2662 	continue;
2663       }
2664       if (dbdeg!=gcddeg)
2665 	continue;
2666       // Same gcd degree for 1st and 2nd try, keep this degree
2667       if (dim!=2) nzero=find_nonzero(db,vzerotmp); else nzero=0;
2668       if (nzero){
2669 	vzero = vzero | vzerotmp;
2670 	// Recompute nzero, it is the number of 0 coeff of vzero
2671 	index_t::const_iterator it=vzero.begin(),itend=vzero.end();
2672 	for (nzero=0;it!=itend;++it){
2673 	  if (!*it)
2674 	    ++nzero;
2675 	}
2676       }
2677       ++essai;
2678     } // end for (essai)
2679     hashgcd_U lcoeffpu,lcoeffqu;
2680     if (debug_infolevel>20-dim)
2681       CERR << "gcdmod lcoeff begin " << "dim " << dim << " " << CLOCK() << '\n';
2682     lcoeffpu=lcoeff(p,varxn,var2,lcoeffp);
2683     lcoeffqu=lcoeff(q,varxn,var2,lcoeffq);
2684     gcdsmallmodpoly(lcoeffp,lcoeffq,modulo,Delta);
2685     if (debug_infolevel>20-dim){
2686       CERR << "lcoeff p, q, gcd" << lcoeffp << "," << lcoeffq << "," << Delta << '\n';
2687       CERR << "gcdmod lcoeff end " << "dim " << dim << " " << CLOCK() << '\n';
2688     }
2689     // estimate time for full lift or division try
2690     // size=p.size()+q.size()
2691     // sumdeg=pxndeg+qxndeg
2692     // %age=gcddeg/min(pxndeg,qxndeg)
2693     // %age^dim*(1-%age)^dim*size^2 estimates the time for division try
2694     // gcddeg*size estimates the time for lifting to gcddeg
2695     // sumdeg*size estimates the time for full lifting
2696     // if sumdeg<(gcddeg+%age^dim*(1-%age)^dim*size) do full lifting
2697     int Deltadeg = int(Delta.size())-1,liftdeg=(compute_qcofactor?qxndeg:pxndeg)+Deltadeg;
2698     int gcddeg_plus_delta=gcddeg+Deltadeg;
2699     int liftdeg0=giacmax(liftdeg-gcddeg,gcddeg_plus_delta);
2700     // once liftdeg0 is reached we can replace g/gp/gq computation
2701     // by a check that d*dp=dxn*lcoeff(d*dp)/Delta at alpha
2702     // and d*dq=dxn*lcoeff(d*dq)/lcoeff(qxn) at alpha
2703     int sumdeg = pxndeg+qxndeg;
2704     double percentage = double(gcddeg)/giacmin(pxndeg,qxndeg);
2705     int sumsize = int(p.size()+q.size());
2706     // ? add a malus factor for division, especially for // threads
2707     double gcdlift=gcddeg+std::pow(percentage,dim)*std::pow(1-percentage,dim)*sumsize;
2708     bool compute_cof = dim==2 || sumdeg<gcdlift;
2709     // we are now interpolating G=gcd(p,q)*a poly/xn
2710     // such that the leading coeff of G is Delta
2711     if (debug_infolevel>20-dim)
2712       CERR << "gcdmod degree begin " << "dim " << dim << " " << CLOCK() << " compute_cof " << compute_cof << "(" << sumdeg/gcdlift << ")" << '\n';
2713     int ptotaldeg=degree(p,shift_vars,pdeg);
2714     int qtotaldeg=degree(q,shift_vars,qdeg);
2715     shift_vars.pop_back();
2716     if (debug_infolevel>20-dim){
2717       CERR << "pdeg " << pdeg << " " << ptotaldeg << '\n';
2718       CERR << "qdeg " << qdeg << " " << qtotaldeg << '\n';
2719     }
2720     if (debug_infolevel>20-dim)
2721       CERR << "gcdmod degree end " << "dim " << dim << " " << CLOCK() << '\n';
2722     int spdeg=0,sqdeg=0;
2723     for (int i=0;i<dim-1;++i){
2724       spdeg += pdeg[i];
2725       sqdeg += qdeg[i];
2726     }
2727     index_gcd(pdeg,qdeg,delta);
2728     delta.pop_back();
2729     int e=0; // number of evaluations
2730     int alpha,alpha1;
2731     if (debug_infolevel>20-dim)
2732       CERR << "gcdmod find alpha dim " << dim << " " << CLOCK() << '\n';
2733     if (debug_infolevel>25-dim)
2734       CERR << " p " << p << " q " << q << '\n';
2735     vector< T_unsigned<int,hashgcd_U> > palpha,qalpha,dp,dq,tmp1interp,tmp2interp; // d, dp and dq are the current interpolated values of gcd and cofactors
2736     vector< vector< T_unsigned<int,hashgcd_U> > > gcdv,pcofactorv,qcofactorv;
2737     // for dim 2
2738     bool dim2 = dim==2 && compute_cof;
2739     if (dim2){
2740       dim2gcdv.resize(liftdeg0+1);
2741       dim2pcofactorv.resize(liftdeg0+1);
2742       dim2qcofactorv.resize(liftdeg0+1);
2743       for (int i=0;i<=liftdeg0;++i){
2744 	dim2gcdv[i].reserve(gcddeg+1);
2745 	dim2pcofactorv[i].reserve(pxndeg-gcddeg+1);
2746 	dim2qcofactorv[i].reserve(qxndeg-gcddeg+1);
2747       }
2748     }
2749     else {
2750       gcdv.reserve(liftdeg0+1);
2751       pcofactorv.reserve(liftdeg0+1);
2752       qcofactorv.reserve(liftdeg0+1);
2753     }
2754     gcd_call_param<int> gcd_par;
2755     gcd_par.Delta=&Delta;
2756     gcd_par.lcoeffp=&lcoeffp;
2757     gcd_par.lcoeffq=&lcoeffq;
2758     gcd_par.alphav=&alphav;
2759     gcd_par.pv=&pv;
2760     gcd_par.qv=&qv;
2761     gcd_par.dv=&dv;
2762     gcd_par.dpv=&dpv;
2763     gcd_par.dim2gcdv=&dim2gcdv;
2764     gcd_par.dim2pcofactorv=&dim2pcofactorv;
2765     gcd_par.dim2qcofactorv=&dim2qcofactorv;
2766     gcd_par.dim2palphaptr=0;
2767     gcd_par.dim2qalphaptr=0;
2768     gcd_par.p=&p;
2769     gcd_par.q=&q;
2770     gcd_par.gcdv=&gcdv;
2771     gcd_par.pcofactorv=&pcofactorv;
2772     gcd_par.qcofactorv=&qcofactorv;
2773     gcd_par.pdeg=&pdeg;
2774     gcd_par.qdeg=&qdeg;
2775     gcd_par.vars=&vars;
2776     gcd_par.vars_truncated=&vars_truncated;
2777     // gcd_par.shift_vars=&shift_vars;
2778     gcd_par.shift_vars_truncated=&shift_vars;
2779     gcd_par.compute_cof=compute_cof;
2780     gcd_par.compute_qcofactor=compute_qcofactor;
2781     gcd_par.dim2=dim2;
2782     gcd_par.modulo=modulo;
2783     if (0 && dim>4
2784 	//0 && (dim>3 || (dim==3 && sumsize*ptotaldeg*4 > modgcd_cachesize ))
2785 	){
2786       gcd_par.nthreads=nthreads;
2787       nthreads=1;
2788     }
2789     else
2790       gcd_par.nthreads=1;
2791     if (debug_infolevel>20-dim && nthreads>1)
2792       CERR << "nthreads " << nthreads << " dim " << dim << " " << sumsize << " " << sumsize*ptotaldeg << '\n';
2793     if (nthreads>gcddeg_plus_delta)
2794       nthreads=gcddeg_plus_delta+1;
2795     if (nthreads>1){
2796       int todo=compute_cof?(liftdeg0+1):(gcddeg_plus_delta+1);
2797       double nth=todo/double(nthreads);
2798       // if (nthreads>=4 && (todo%nthreads==0)) nth = (todo+1)/double(nthreads); // keep one proc for a bad prime
2799       nth=std::ceil(nth);
2800       nthreads=int(std::ceil(todo/nth));
2801       if (debug_infolevel>20-dim)
2802 	CERR << "Using " << nthreads << " threads " << nth << " " << todo/nth << '\n';
2803     }
2804     for (alpha=-1;;){
2805       // Possible improvement: if gcddeg is high, cofactors will stabilize
2806       // soon, then gcd could be obtained by division instead of interp
2807       // First check if we are ready to interpolate
2808       if (!compute_cof && e>gcddeg_plus_delta){
2809 	if (dim2)
2810 	  interpolate_dim2_convert(alphav,dim2gcdv,d,varxn,var2,modulo);
2811 	else
2812 	  interpolate(alphav,gcdv,d,var2,modulo,tmp1interp,tmp2interp);
2813 	if (debug_infolevel>20-dim)
2814 	  CERR << "gcdmod pp1mod dim " << dim << " " << CLOCK() << " d " << d << '\n';
2815 	vector< T_unsigned<int,hashgcd_U> > pquo,qquo,tmprem,pD(d);
2816 	pp_mod_last(pD,0,modulo,varxn,var2,tmpcont);
2817 	// This removes the polynomial in xn that we multiplied by
2818 	// (it was necessary to know the lcoeff of the interpolated poly)
2819 	if (debug_infolevel>20-dim)
2820 	  CERR << "gcdmod check dim " << dim << " " << CLOCK() << '\n';
2821 	// Now, gcd divides pD for gcddeg+1 values of x1
2822 	// degree(pD)<=degree(gcd)
2823 	// gcd_mutex_lock();
2824 	if (hashdivrem(p,pD,pquo,tmprem,vars,modulo,0,false,0/* 0:default, 1: check divisibility only heap div*/)==1 && tmprem.empty()){
2825 	  // If pD divides both P and Q, then the degree wrt variables
2826 	  // x1,...,xn-1 is the right one (because it is <= since pD
2827 	  // divides the gcd and >= since pD(xn=one of the try) was a gcd
2828 	  // The degree in xn is the right one because of the condition
2829 	  // on the lcoeff
2830 	  // Note that the division test might be much longer than the
2831 	  // interpolation itself (e.g. if the degree of the gcd is small)
2832 	  // but it seems unavoidable, for example if
2833 	  // P=Y-X+X(X-1)(X-2)(X-3)
2834 	  // Q=Y-X+X(X-1)(X-2)(X-4)
2835 	  // then gcd(P,Q)=1, but if we take Y=0, Y=1 or Y=2
2836 	  // we get gcddeg=1 (probably degree 1 for the gcd)
2837 	  // interpolation at X=0 and X=1 will lead to Y-X as candidate gcd
2838 	  // and even adding X=2 will not change it
2839 	  // We might remove division if we compute the cofactors of P and Q
2840 	  // if P=pD*cofactor is true for degree(P) values of x1
2841 	  // and same for Q, and the degrees wrt xn of pD and cofactors
2842 	  // have sum equal to degree of P or Q + lcoeff then pD is the gcd
2843 	  if (hashdivrem(q,pD,qquo,tmprem,vars,modulo,0,false,0)==1 && tmprem.empty()){
2844 	    // gcd_mutex_unlock();
2845 	    if (dcont.size()==1 && dcont.front().g==1 && dcont.front().u==0)
2846 	      d.swap(pD);
2847 	    else
2848 	      smallmult(pD,dcont,d,modulo,0);
2849 	    smallmult(invmod(d.front().g,modulo),d,d,modulo);
2850 	    if (compute_pcofactor){
2851 	      smallmult(pcofactor,pquo,pcofactor,modulo,0);
2852 	      smallmult(smod(longlong(p_orig.front().g)*invmod(pcofactor.front().g,modulo),modulo),pcofactor,pcofactor,modulo);
2853 	    }
2854 	    if (compute_qcofactor){
2855 	      smallmult(qcofactor,qquo,qcofactor,modulo,0);
2856 	      smallmult(smod(longlong(q_orig.front().g)*invmod(qcofactor.front().g,modulo),modulo),qcofactor,qcofactor,modulo);
2857 	    }
2858 	    if (debug_infolevel>20-dim)
2859 	      CERR << "gcdmod found dim " << dim << " " << CLOCK() << '\n';
2860 	    if (pqswap)
2861 	      swap(pcofactor,qcofactor);
2862 	    return true;
2863 	  } // end if hashdivrem(q,...)
2864 	} // end if hashdivrem(p,...)
2865 	//gcd_mutex_unlock();
2866 	if (debug_infolevel>20-dim)
2867 	  CERR << "Gcdmod bad guess " << '\n';
2868 	// restart
2869 	gcdv.clear(); alphav.clear();
2870 	pcofactorv.clear(); qcofactorv.clear();
2871 	// dim2gcdv.clear(); dim2pcofactorv.clear(); dim2qcofactorv.clear();
2872 	e=0;
2873       } // end if (e>gcddeg+delta)
2874       if (compute_cof && e>liftdeg0 ){
2875 	// interpolate d and dp
2876 	if (dim2){
2877 	  interpolate_dim2(alphav,dim2gcdv,dv,modulo);
2878 	  if (debug_infolevel>20-dim)
2879 	    CERR << "end interpolate gcd " << CLOCK() << '\n';
2880 	  convert_back(dv,varxn,var2,d);
2881 	  interpolate_dim2(alphav,dim2pcofactorv,dpv,modulo);
2882 	  convert_back(dpv,varxn,var2,dp);
2883 	  if (debug_infolevel>20-dim)
2884 	    CERR << "end interpolate p cof " << CLOCK() << '\n';
2885 	}
2886 	else {
2887 	  interpolate(alphav,gcdv,d,var2,modulo,tmp1interp,tmp2interp);
2888 	  if (debug_infolevel>20-dim)
2889 	    CERR << "end interpolate gcd " << CLOCK() << '\n';
2890 	  interpolate(alphav,pcofactorv,dp,var2,modulo,tmp1interp,tmp2interp);
2891 	  if (debug_infolevel>20-dim)
2892 	    CERR << "end interpolate p cof " << CLOCK() << '\n';
2893 	}
2894 	// check that d(alpha)*dp(alpha)=palpha with lcoeff adjusted
2895 	// for e<=liftdeg
2896 	if (dim2){
2897 	  vector<int> dv1,dpv1;
2898 	  for (++alpha;e<=liftdeg;++e,++alpha){
2899 	    alpha1=alpha%2?-(alpha+1)/2:alpha/2;
2900 	    while (hornermod(lcoeffp,alpha1,modulo)==0){
2901 	      ++alpha;
2902 	      alpha1=alpha%2?-(alpha+1)/2:alpha/2;
2903 	    }
2904 #ifdef TIMEOUT
2905 	    control_c();
2906 #endif
2907 	    if (ctrl_c || interrupted || alpha>=modulo)
2908 	      return false;
2909 	    int maxtotaldeg=ptotaldeg+1-e;
2910 	    horner_back(pv,alpha1,dim2palpha,modulo,maxtotaldeg,true);
2911 	    horner_back(dv,alpha1,dv1,modulo,maxtotaldeg,true);
2912 	    horner_back(dpv,alpha1,dpv1,modulo,maxtotaldeg,true);
2913 	    if (debug_infolevel>20){
2914 	      CERR << "palpha " << dim2palpha << '\n';
2915 	      CERR << "gcd alpha " << dv1 << '\n';
2916 	      CERR << "p-cof alpha " << dpv1 << '\n';
2917 	    }
2918 	    mulmod(dpv1,smod(longlong(hornermod(pv.front(),alpha1,modulo))*invmod((hornermod(dv.front(),alpha1,modulo)*longlong(hornermod(dpv.front(),alpha1,modulo)))%modulo,modulo),modulo),modulo);
2919 	    if (!is_p_a_times_b(dim2palpha,dpv1,dv1,modulo,maxtotaldeg)){
2920 	      e=liftdeg0+1;
2921 	      break;
2922 	    }
2923 	  }
2924 	}
2925 	else {
2926 	  vector< T_unsigned<int,hashgcd_U> > g,gp;
2927 	  for (++alpha;e<=liftdeg;++e,++alpha){
2928 	    alpha1=alpha%2?-(alpha+1)/2:alpha/2;
2929 	    while (hornermod(lcoeffp,alpha1,modulo)==0){
2930 	      ++alpha;
2931 	      alpha1=alpha%2?-(alpha+1)/2:alpha/2;
2932 	    }
2933 #ifdef TIMEOUT
2934 	    control_c();
2935 #endif
2936 	    if (ctrl_c || interrupted || alpha>=modulo)
2937 	      return false;
2938 	    int maxtotaldeg=ptotaldeg+1-e;
2939 	    if (!horner(p,alpha1,vars,palpha,modulo,maxtotaldeg))
2940 	      return false;
2941 	    if (debug_infolevel>20-dim)
2942 	      CERR << "gcdmod horner d " << alpha << " dim " << dim << " " << CLOCK() << '\n';
2943 	    if (!horner(d,alpha1,vars,g,modulo,maxtotaldeg))
2944 	      return false;
2945 	    if (debug_infolevel>20-dim)
2946 	      CERR << "gcdmod horner dp " << alpha << " dim " << dim << " " << CLOCK() << '\n';
2947 	    if (!horner(dp,alpha1,vars,gp,modulo,maxtotaldeg))
2948 	      return false;
2949 	    smallmult(smod(longlong(palpha.back().g)*invmod((gp.back().g*longlong(g.back().g))%modulo,modulo),modulo),gp,gp,modulo);
2950 	    if (!is_p_a_times_b(palpha,gp,g,vars,modulo,maxtotaldeg)){
2951 	      // Bad guess, go find some new gcd and interpolate
2952 	      e=liftdeg0+1;
2953 	      break;
2954 	    }
2955 	  } // end for ( e loop )
2956 	}
2957 	if (e>liftdeg){
2958 	  // enough evaluation point
2959 	  // divide d,dp,dq by their content in xn
2960 	  pp_mod_last(d,0,modulo,varxn,var2,tmpcont);
2961 	  pp_mod_last(dp,0,modulo,varxn,var2,tmpcont);
2962 	  // check xn degrees of d+dp=degree(pxn), d+dq=degree(qxn)
2963 	  int dxndeg=degree_xn(d,shiftxn,shift2),dpxndeg=degree_xn(dp,shiftxn,shift2);
2964 	  // int dqxndeg=degree_xn(dq,shiftxn,shift2);
2965 	  if ( dxndeg+dpxndeg==pdeg.back() ){
2966 	    if (dcont.size()!=1 || dcont.front().u!=0)
2967 	      smallmult(d,dcont,d,modulo,0);
2968 	    if (compute_pcofactor){
2969 	      smallmult(dp,pcofactor,pcofactor,modulo,0);
2970 	      smallmult(smod(longlong(p_orig.front().g)*invmod(pcofactor.front().g,modulo),modulo),pcofactor,pcofactor,modulo);
2971 	    }
2972 	    if (compute_qcofactor){
2973 	      if (dim2)
2974 		interpolate_dim2_convert(alphav,dim2qcofactorv,dq,varxn,var2,modulo);
2975 	      else
2976 		interpolate(alphav,qcofactorv,dq,var2,modulo,tmp1interp,tmp2interp);
2977 	      pp_mod_last(dq,0,modulo,varxn,var2,tmpcont);
2978 	      smallmult(dq,qcofactor,qcofactor,modulo,0);
2979 	      smallmult(smod(longlong(q_orig.front().g)*invmod(qcofactor.front().g,modulo),modulo),qcofactor,qcofactor,modulo);
2980 	    }
2981 	    if (debug_infolevel>20-dim)
2982 	      CERR << "gcdmod end dim " << dim << " " << CLOCK() << '\n';
2983 	    if (pqswap){
2984 	      swap(pcofactor,qcofactor);
2985 	      swap(dim2pcofactorv,dim2qcofactorv);
2986 	    }
2987 	    divtest=false;
2988 	    return true;
2989 	  }
2990 	  // failure, restart
2991 	  gcdv.clear(); alphav.clear(); dim2gcdv.clear();
2992 	  pcofactorv.clear(); qcofactorv.clear();
2993 	  dim2pcofactorv.clear(); dim2qcofactorv.clear();
2994 	  e=0;
2995 	} // end if (e>lifdeg)
2996       } // end if (compute_cof && e in liftdeg0..liftdeg)
2997 
2998       // *************************************************** //
2999       // Not ready to interpolate, try to eval new points
3000       // *************************************************** //
3001 
3002       for (int thread=0;thread<nthreads;++thread){
3003 	// find a good alpha with respect to leading coeff
3004 	for (;;){
3005 	  ++alpha;
3006 #ifdef TIMEOUT
3007 	  control_c();
3008 #endif
3009 	  if (ctrl_c || interrupted || alpha==modulo){
3010 	    CERR << "Modgcd: no suitable evaluation point" << '\n';
3011 	    return false;
3012 	  }
3013 	  alpha1=alpha%2?-(alpha+1)/2:alpha/2;
3014 	  if (hornermod(lcoeffp,alpha1,modulo)==0 || hornermod(lcoeffq,alpha1,modulo)==0)
3015 	    continue;
3016 	  if (debug_infolevel>20-dim)
3017 	    CERR << "gcdmod eval alpha1=" << alpha1 << " dim " << dim << " " << CLOCK() << '\n';
3018 	  break;
3019 	} // end for (;;)
3020 	// alpha is probably admissible
3021 	// (we will test later if degree of palpha/qalpha wrt x1...xn-1 is max)
3022 	// prepare room for gcd and cofactors
3023 	if (debug_infolevel>25-dim)
3024 	  CERR << "dim " << dim << " palpha " << palpha << " qalpha " << qalpha << '\n' ;
3025 	alphav.push_back(alpha1);
3026 	if (dim2){
3027 	  if (alphav.size()>dim2gcdv.size()){
3028 	    dim2gcdv.push_back(vector<int>(0));
3029 	    dim2pcofactorv.push_back(vector<int>(0));
3030 	    dim2qcofactorv.push_back(vector<int>(0));
3031 	  }
3032 	}
3033 	else {
3034 	  gcdv.push_back(vector< T_unsigned<int,hashgcd_U> >(0));
3035 	  pcofactorv.push_back(vector< T_unsigned<int,hashgcd_U> >(0));
3036 	  qcofactorv.push_back(vector< T_unsigned<int,hashgcd_U> >(0));
3037 	}
3038       } // end for (int thread=0;thread<nthreads;++thread)
3039 #if 1
3040       gcd_call_param<int> * gcd_call_param_v=(gcd_call_param<int> *)alloca(nthreads*sizeof(gcd_call_param<int>));
3041       for (int i=0;i<nthreads;++i)
3042 	gcd_call_param_v[i]=gcd_par;
3043 #else
3044       vector<gcd_call_param<int> > gcd_call_param_v(nthreads,gcd_par);
3045 #endif
3046       gcd_call_param_v[nthreads-1].dim2palphaptr=&dim2palpha_nthreads;
3047       gcd_call_param_v[nthreads-1].dim2qalphaptr=&dim2qalpha_nthreads;
3048 #ifdef HAVE_PTHREAD_H
3049       pthread_t tab[nthreads-1];
3050 #endif
3051       for (int thread=0;thread<nthreads;++thread){
3052 	int vpos=int(alphav.size())-(nthreads-thread);
3053 	gcd_call_param_v[thread].vpos=vpos;
3054 	if (thread!=nthreads-1 && !dim2){
3055 	  gcd_call_param_v[thread].pv=0;
3056 	  gcd_call_param_v[thread].qv=0;
3057 	}
3058 #ifdef HAVE_PTHREAD_H
3059 	if (thread==nthreads-1)
3060 	  do_recursive_gcd_call((void *)&gcd_call_param_v[thread]);
3061 	else { // launch gcd computation in a separate thread
3062 	  bool res=pthread_create(&tab[thread],(pthread_attr_t *) NULL,do_recursive_gcd_call,(void *) &gcd_call_param_v[thread]);
3063 	  if (res)
3064 	    do_recursive_gcd_call((void *)&gcd_call_param_v[thread]);
3065 	}
3066 #else
3067 	do_recursive_gcd_call((void *)&gcd_call_param_v[thread]);
3068 #endif
3069       }
3070 #ifdef TIMEOUT
3071       control_c();
3072 #endif
3073       if (ctrl_c || interrupted)
3074 	return false;
3075 #ifdef HAVE_PTHREAD_H
3076       for (int thread=0;thread<nthreads-1;++thread){
3077 	int vpos=alphav.size()-(nthreads-thread);
3078 	// wait for thread to finish
3079 	void * ptr;
3080 	pthread_join(tab[thread],&ptr);
3081 	if (!ptr){
3082 	  if (dim2)
3083 	    dim2gcdv[vpos].clear();
3084 	  else
3085 	    gcdv[vpos].clear();
3086 	}
3087       }
3088 #endif
3089       for (int thread=0;thread<nthreads;++thread){
3090 	int vpos=int(alphav.size())-(nthreads-thread);
3091 	// Compare gcd degree in x1..xn-1, 0 means trash this value of alpha1
3092 	int comp=0;
3093 	if ( dim2 ? (!dim2gcdv[vpos].empty()) : (!gcdv[vpos].empty()) ){
3094 	  if (dim2)
3095 	    gdeg[0]=int(dim2gcdv[vpos].size())-1;
3096 	  else
3097 	    degree(gcdv[vpos],shift_vars,gdeg);
3098 	  comp=compare(gdeg,delta);
3099 	}
3100 	if (comp==-2){
3101 	  // same degrees, add to interpolation
3102 	  // Try spmod first
3103 	  if (!compute_cof && nzero){
3104 	    // Add alpha,g
3105 	    if (dim>2 && gcddeg-nzero==e){
3106 	      if (debug_infolevel>20-dim)
3107 		CERR << CLOCK()*1e-6 << " SPMOD begin" << '\n';
3108 	      // We have enough evaluations, let's try SPMOD
3109 	      // memory allocations
3110 	      // estimate memory required
3111 	      size_t taille=0;
3112 	      for (int k=0;k<=e;++k){
3113 		if (taille<gcdv[k].size()) taille=gcdv[k].size();
3114 		// taille += gcdv[k].size();
3115 	      }
3116 	      vector< vector< T_unsigned<int,hashgcd_U> > > minversegcd(e+1);
3117 	      for (int j=0;j<=e;++j)
3118 		minversegcd[j].reserve(taille);
3119 	      vector< T_unsigned<int,hashgcd_U> > tmpadd,tmpmult;
3120 	      tmpadd.reserve(taille);
3121 	      //tmpmult.reserve(taille); // max of sizes of gcdv[k]
3122 	      vector< vector<int> > m(e+1),minverse;
3123 	      for (int j=0;j<=e;++j){
3124 		m[j].reserve(e+1);
3125 	      }
3126 	      // Build the matrix, each line has coeffs / vzero
3127 	      for (int j=0;j<=e;++j){
3128 		index_t::reverse_iterator it=vzero.rbegin(),itend=vzero.rend();
3129 		vector<int> & line = m[j];
3130 		longlong p=alphav[j]; // avoid overflow
3131 		for (int pp=1;it!=itend;++it,pp=smod(p*pp,modulo)){
3132 		  if (*it)
3133 		    line.push_back(pp);
3134 		}
3135 		reverse(line.begin(),line.end());
3136 	      }
3137 	      // assume gcd is the vector of non zero coeffs of the gcd in x^n
3138 	      // we have the relation
3139 	      // m*gcd=gcdv
3140 	      // invert m (if invertible)
3141 	      longlong det_mod_p;
3142 	      if (smallmodinv(m,minverse,modulo,det_mod_p) && det_mod_p){
3143 		// hence gcd=minverse*gcdv, where the i-th component of gcd
3144 		// must be "multiplied" by xn^degree_corresponding_vzero[i]
3145 		size_t taille2=0;
3146 		for (int j=0;j<=e;++j){
3147 		  for (int k=0;k<=e;++k){
3148 #if 0
3149 		    //tmpmult.clear(); copy(gcdv[k].begin(),gcdv[k].end(),tmpmult.begin());
3150 		    tmpmult=gcdv[k];
3151 		    smallmult(minverse[j][k],tmpmult,tmpmult,modulo);
3152 		    tmpadd.swap(minversegcd[j]);
3153 		    smalladd(tmpadd,tmpmult,minversegcd[j],modulo);
3154 #else
3155 		    if (!is_zero(minverse[j][k])){
3156 		      tmpadd.swap(minversegcd[j]);
3157 		      smalladdmult(tmpadd,minverse[j][k],gcdv[k],minversegcd[j],modulo);
3158 		    }
3159 #endif
3160 		    // CERR << minversegcd[j] << '\n';
3161 		  }
3162 		  taille2 += minversegcd[j].size();
3163 		}
3164 		vector< T_unsigned<int,hashgcd_U> > trygcd,pquo,qquo,tmprem;
3165 		trygcd.reserve(taille2);
3166 		tmprem.reserve(taille2);
3167 		index_t::const_iterator it=vzero.begin(),itend=vzero.end();
3168 		int deg=int(itend-it)-1;
3169 		for (int j=0;it!=itend;++it,--deg){
3170 		  if (!*it)
3171 		    continue;
3172 		  smallshift(minversegcd[j],deg*var2,minversegcd[j]);
3173 #if 1
3174 		  tmprem.swap(trygcd);
3175 		  smalladd(tmprem,minversegcd[j],trygcd,modulo);
3176 #else
3177 		  smalladd(trygcd,minversegcd[j],trygcd,modulo);
3178 #endif
3179 		  ++j;
3180 		}
3181 		if (0){
3182 		  CERR << "trygcd " << trygcd.size() << " " << trygcd.capacity() << '\n';
3183 		  for (int j=0;j<=e;++j)
3184 		    CERR << "minversegcd[" << j << "] " << minversegcd[j].size()<< " " << minversegcd[j].capacity() << '\n';
3185 		}
3186 		// Check if trygcd is the gcd!
3187 		if (debug_infolevel>20-dim)
3188 		  CERR << CLOCK()*1e-6 << " SPMOD trygcd" << '\n';
3189 		pp_mod_last(trygcd,0,modulo,varxn,var2,tmpcont);
3190 		if (hashdivrem(p,trygcd,pquo,tmprem,vars,modulo,0,false)==1 && tmprem.empty()){
3191 		  if (hashdivrem(q,trygcd,qquo,tmprem,vars,modulo,0,false)==1 && tmprem.empty()){
3192 		    if (dcont.size()==1 && dcont.front().g==1 && dcont.front().u==0)
3193 		      d.swap(trygcd);
3194 		    else
3195 		      smallmult(trygcd,dcont,d,modulo,0);
3196 		    smallmult(invmod(d.front().g,modulo),d,d,modulo);
3197 		    if (compute_pcofactor){
3198 		      smallmult(pcofactor,pquo,pcofactor,modulo,0);
3199 		    smallmult(smod(longlong(p_orig.front().g)*invmod(pcofactor.front().g,modulo),modulo),pcofactor,pcofactor);
3200 		    }
3201 		    if (compute_qcofactor){
3202 		      smallmult(qcofactor,qquo,qcofactor,modulo,0);
3203 		      smallmult(smod(longlong(q_orig.front().g)*invmod(qcofactor.front().g,modulo),modulo),qcofactor,qcofactor);
3204 		    }
3205 		    if (debug_infolevel>20-dim)
3206 		      CERR << "gcdmod found dim " << dim << " " << CLOCK() << '\n';
3207 		    if (pqswap){
3208 		      swap(pcofactor,qcofactor);
3209 		      swap(dim2pcofactorv,dim2qcofactorv);
3210 		    }
3211 		    return true;
3212 		  } // end q divisible by trygcd
3213 		} // end p divisible by trygcd
3214 	      } // end m invertible
3215 	    } // end if (dim>2 && gcddeg-nzero==e)
3216 	  } // end if (!compute_cof && nzero)
3217 	  if (debug_infolevel>20-dim)
3218 	    CERR << "gcdmod interp dim " << dim << " " << CLOCK() << '\n';
3219 	  ++e;
3220 	  continue;
3221 	} // end gdeg==delta
3222 	if (comp==0 || comp==-1){
3223 	  if (debug_infolevel>20-dim)
3224 	    CERR << "Bad reduction " << alphav[vpos] << '\n';
3225 	  // bad reduction: all indices of gdeg are >= to delta and gdeg!=delta
3226 	  alphav.erase(alphav.begin()+vpos);
3227 	  if (dim2){
3228 	    //dim2gcdv.erase(dim2gcdv.begin()+vpos);
3229 	    //dim2pcofactorv.erase(dim2pcofactorv.begin()+vpos);
3230 	    //dim2qcofactorv.erase(dim2qcofactorv.begin()+vpos);
3231 	  }
3232 	  else {
3233 	    gcdv.erase(gcdv.begin()+vpos);
3234 	    pcofactorv.erase(pcofactorv.begin()+vpos);
3235 	    qcofactorv.erase(qcofactorv.begin()+vpos);
3236 	  }
3237 	  if (comp==0)
3238 	    continue;
3239 	}
3240 	// previous alpha where bad reduction
3241 	if (debug_infolevel>20-dim && vpos)
3242 	  CERR << "Bads reductions " << alphav[vpos-1] << '\n';
3243 	alphav.erase(alphav.begin(),alphav.begin()+vpos);
3244 	if (dim2){
3245 	  dim2gcdv[0].swap(dim2gcdv[vpos]);// dim2gcdv.erase(dim2gcdv.begin(),dim2gcdv.begin()+vpos);
3246 	  dim2pcofactorv[0].swap(dim2pcofactorv[vpos]); // dim2pcofactorv.erase(dim2pcofactorv.begin(),dim2pcofactorv.begin()+vpos);
3247 	  dim2qcofactorv[0].swap(dim2qcofactorv[vpos]); // dim2qcofactorv.erase(dim2qcofactorv.begin(),dim2qcofactorv.begin()+vpos);
3248 	}
3249 	else {
3250 	  gcdv.erase(gcdv.begin(),gcdv.begin()+vpos);
3251 	  pcofactorv.erase(pcofactorv.begin(),pcofactorv.begin()+vpos);
3252 	  qcofactorv.erase(qcofactorv.begin(),qcofactorv.begin()+vpos);
3253 	}
3254 	if (comp==-1){
3255 	  e=0;
3256 	  continue;
3257 	}
3258 	// restart everything with this value of alpha
3259 	// this will happen (almost all the time) at first iteration
3260 	delta=gdeg;
3261 	e=1;
3262 	continue;
3263       } // end for (int thread=0;thread<nthreads;++thread)
3264     } // end for (alpha=-1;;)
3265 #endif // NO_TEMPLATE_MULTGCD
3266   }
3267 
mod_gcd(const std::vector<T_unsigned<int,hashgcd_U>> & p_orig,const std::vector<T_unsigned<int,hashgcd_U>> & q_orig,int modulo,std::vector<T_unsigned<int,hashgcd_U>> & d,std::vector<T_unsigned<int,hashgcd_U>> & pcofactor,std::vector<T_unsigned<int,hashgcd_U>> & qcofactor,const std::vector<hashgcd_U> & vars,bool compute_pcofactor,bool compute_qcofactor,int nthreads)3268   bool mod_gcd(const std::vector< T_unsigned<int,hashgcd_U> > & p_orig,const std::vector< T_unsigned<int,hashgcd_U> > & q_orig,int modulo,std::vector< T_unsigned<int,hashgcd_U> > & d, std::vector< T_unsigned<int,hashgcd_U> > & pcofactor, std::vector< T_unsigned<int,hashgcd_U> > & qcofactor,const std::vector<hashgcd_U> & vars, bool compute_pcofactor,bool compute_qcofactor,int nthreads){
3269     bool divtest;
3270     vector< vector<int> > pv,qv,dv,dpv,dim2gcdv,dim2pcofactorv,dim2qcofactorv;
3271     return mod_gcd(p_orig,q_orig,modulo,d,pcofactor,qcofactor,vars,compute_pcofactor,compute_qcofactor,divtest,pv,qv,dv,dpv,dim2gcdv,dim2pcofactorv,dim2qcofactorv,nthreads);
3272   }
3273 
mod_gcd(const std::vector<T_unsigned<int,hashgcd_U>> & p_orig,const std::vector<T_unsigned<int,hashgcd_U>> & q_orig,int modulo,std::vector<T_unsigned<int,hashgcd_U>> & d,std::vector<T_unsigned<int,hashgcd_U>> & pcofactor,std::vector<T_unsigned<int,hashgcd_U>> & qcofactor,const std::vector<hashgcd_U> & vars,bool compute_cofactors,int nthreads)3274   bool mod_gcd(const std::vector< T_unsigned<int,hashgcd_U> > & p_orig,const std::vector< T_unsigned<int,hashgcd_U> > & q_orig,int modulo,std::vector< T_unsigned<int,hashgcd_U> > & d, std::vector< T_unsigned<int,hashgcd_U> > & pcofactor, std::vector< T_unsigned<int,hashgcd_U> > & qcofactor,const std::vector<hashgcd_U> & vars, bool compute_cofactors,int nthreads){
3275     return mod_gcd(p_orig,q_orig,modulo,d,pcofactor,qcofactor,vars,compute_cofactors,compute_cofactors,nthreads);
3276   }
3277 
3278 #if 0
3279   static void smod(vector< T_unsigned<int,hashgcd_U> > & p_orig,int modulo){
3280     vector< T_unsigned<int,hashgcd_U> >::iterator it=p_orig.begin(),itend=p_orig.end();
3281     for (;it!=itend;++it){
3282       it->g=smod(it->g,modulo);
3283     }
3284   }
3285 #endif
3286 
smod(const vector<T_unsigned<gen,hashgcd_U>> & p_orig,int modulo,vector<T_unsigned<int,hashgcd_U>> & p)3287   static void smod(const vector< T_unsigned<gen,hashgcd_U> > & p_orig,int modulo,vector< T_unsigned<int,hashgcd_U> > & p){
3288     p.clear();
3289     vector< T_unsigned<gen,hashgcd_U> >::const_iterator it=p_orig.begin(),itend=p_orig.end();
3290     p.reserve(itend-it);
3291     int x;
3292     for (;it!=itend;++it){
3293       x=smod(it->g,modulo).val;
3294       if (x)
3295 	p.push_back(T_unsigned<int,hashgcd_U>(x,it->u));
3296     }
3297   }
3298 
unmod(const vector<T_unsigned<int,hashgcd_U>> & p_orig,vector<T_unsigned<gen,hashgcd_U>> & p,int modulo)3299   static void unmod(const vector< T_unsigned<int,hashgcd_U> > & p_orig,vector< T_unsigned<gen,hashgcd_U> > & p,int modulo){
3300     p.clear();
3301     vector< T_unsigned<int,hashgcd_U> >::const_iterator it=p_orig.begin(),itend=p_orig.end();
3302     for (;it!=itend;++it){
3303       p.push_back(T_unsigned<gen,hashgcd_U>(smod(it->g,modulo),it->u));
3304     }
3305   }
3306 
complex_unmod(const vector<T_unsigned<int,hashgcd_U>> & p1,const vector<T_unsigned<int,hashgcd_U>> & p2,vector<T_unsigned<gen,hashgcd_U>> & p,int i,int modulo)3307   static void complex_unmod(const vector< T_unsigned<int,hashgcd_U> > & p1,const vector< T_unsigned<int,hashgcd_U> > & p2,vector< T_unsigned<gen,hashgcd_U> > & p,int i,int modulo){
3308     p.clear();
3309     vector< T_unsigned<int,hashgcd_U> >::const_iterator it=p1.begin(),itend=p1.end();
3310     vector< T_unsigned<int,hashgcd_U> >::const_iterator jt=p2.begin(),jtend=p2.end();
3311     // real part is halfsum of p1,p2, imaginary part halfdiff of p1-p2 divided by i (mod modulo)
3312     longlong inv2=invmod(2,modulo), inv2i=invmod(2*i,modulo);
3313     for (;it!=itend && jt!=jtend;){
3314       if (it->u==jt->u){
3315 	p.push_back(T_unsigned<gen,hashgcd_U>(gen(smod(inv2*(it->g+jt->g),modulo),smod(inv2i*(it->g-jt->g),modulo)),it->u));
3316 	++it;
3317 	++jt;
3318 	continue;
3319       }
3320       if (it->u>jt->u){
3321 	p.push_back(T_unsigned<gen,hashgcd_U>(gen(smod(inv2*(it->g),modulo),smod(inv2i*(it->g),modulo)),it->u));
3322 	++it;
3323       }
3324       else {
3325 	p.push_back(T_unsigned<gen,hashgcd_U>(gen(smod(inv2*(jt->g),modulo),smod(inv2i*(-jt->g),modulo)),it->u));
3326 	++jt;
3327       }
3328     }
3329     for (;it!=itend;++it){
3330       p.push_back(T_unsigned<gen,hashgcd_U>(gen(smod(inv2*(it->g),modulo),smod(inv2i*(it->g),modulo)),it->u));
3331     }
3332     for (;jt!=jtend;++jt){
3333       p.push_back(T_unsigned<gen,hashgcd_U>(gen(smod(inv2*(jt->g),modulo),smod(inv2i*(-jt->g),modulo)),it->u));
3334     }
3335   }
3336 
complex_unmod_ext(const vector<T_unsigned<vecteur,hashgcd_U>> & p1,const vector<T_unsigned<vecteur,hashgcd_U>> & p2,vector<T_unsigned<gen,hashgcd_U>> & p,int i,int modulo)3337   static void complex_unmod_ext(const vector< T_unsigned<vecteur,hashgcd_U> > & p1,const vector< T_unsigned<vecteur,hashgcd_U> > & p2,vector< T_unsigned<gen,hashgcd_U> > & p,int i,int modulo){
3338     p.clear();
3339     vector< T_unsigned<vecteur,hashgcd_U> >::const_iterator it=p1.begin(),itend=p1.end();
3340     vector< T_unsigned<vecteur,hashgcd_U> >::const_iterator jt=p2.begin(),jtend=p2.end();
3341     // real part is halfsum of p1,p2, imaginary part halfdiff of p1-p2 divided by i (mod modulo)
3342     gen inv2=invmod(2,modulo), inv2i=invmod(2*i,modulo);
3343     for (;it!=itend && jt!=jtend;){
3344       if (it->u==jt->u){
3345 	p.push_back(T_unsigned<gen,hashgcd_U>( smod(inv2*(it->g+jt->g),modulo)+cst_i*smod(inv2i*(it->g-jt->g),modulo) ,it->u));
3346 	++it;
3347 	++jt;
3348 	continue;
3349       }
3350       if (it->u>jt->u){
3351 	p.push_back(T_unsigned<gen,hashgcd_U>( smod(inv2*(it->g),modulo)+cst_i*smod(inv2i*(it->g),modulo) ,it->u));
3352 	++it;
3353       }
3354       else {
3355 	p.push_back(T_unsigned<gen,hashgcd_U>( smod(inv2*(jt->g),modulo)+cst_i*smod(inv2i*(-jt->g),modulo),it->u));
3356 	++jt;
3357       }
3358     }
3359     for (;it!=itend;++it){
3360       p.push_back(T_unsigned<gen,hashgcd_U>(smod(inv2*(it->g),modulo)+cst_i*smod(inv2i*(it->g),modulo),it->u));
3361     }
3362     for (;jt!=jtend;++jt){
3363       p.push_back(T_unsigned<gen,hashgcd_U>(smod(inv2*(jt->g),modulo)+cst_i*smod(inv2i*(-jt->g),modulo),it->u));
3364     }
3365   }
3366 
ichinrem(const vector<T_unsigned<int,hashgcd_U>> & p_orig,const gen & modulo,vector<T_unsigned<gen,hashgcd_U>> & p,const gen & pimod)3367   static void ichinrem(const vector< T_unsigned<int,hashgcd_U> > & p_orig,const gen & modulo,vector< T_unsigned<gen,hashgcd_U> > & p,const gen & pimod){
3368     vector< T_unsigned<gen,hashgcd_U> > q;
3369     vector< T_unsigned<int,hashgcd_U> >::const_iterator it=p_orig.begin(),itend=p_orig.end();
3370     vector< T_unsigned<gen,hashgcd_U> >::const_iterator jt=p.begin(),jtend=p.end();
3371     q.reserve(jtend-jt);
3372     for (;it!=itend && jt!=jtend;){
3373       if (it->u==jt->u){
3374 	q.push_back(T_unsigned<gen,hashgcd_U>(ichinrem(it->g,jt->g,modulo,pimod),it->u));
3375 	++it; ++jt;
3376 	continue;
3377       }
3378       if (it->u<jt->u){
3379 	q.push_back(T_unsigned<gen,hashgcd_U>(ichinrem(0,jt->g,modulo,pimod),jt->u));
3380 	++jt;
3381       }
3382       else {
3383 	q.push_back(T_unsigned<gen,hashgcd_U>(ichinrem(it->g,zero,modulo,pimod),it->u));
3384 	++it;
3385       }
3386     }
3387     for (;it!=itend;++it)
3388       q.push_back(T_unsigned<gen,hashgcd_U>(ichinrem(it->g,zero,modulo,pimod),it->u));
3389     for (;jt!=jtend;++jt)
3390       q.push_back(T_unsigned<gen,hashgcd_U>(ichinrem(0,jt->g,modulo,pimod),jt->u));
3391     swap(p,q);
3392   }
3393 
ichinrem(const vector<T_unsigned<gen,hashgcd_U>> & p_orig,const gen & modulo,vector<T_unsigned<gen,hashgcd_U>> & p,const gen & pimod)3394   static void ichinrem(const vector< T_unsigned<gen,hashgcd_U> > & p_orig,const gen & modulo,vector< T_unsigned<gen,hashgcd_U> > & p,const gen & pimod){
3395     vector< T_unsigned<gen,hashgcd_U> > q;
3396     vector< T_unsigned<gen,hashgcd_U> >::const_iterator it=p_orig.begin(),itend=p_orig.end();
3397     vector< T_unsigned<gen,hashgcd_U> >::const_iterator jt=p.begin(),jtend=p.end();
3398     q.reserve(jtend-jt);
3399     for (;it!=itend && jt!=jtend;){
3400       if (it->u==jt->u){
3401 	q.push_back(T_unsigned<gen,hashgcd_U>(ichinrem(it->g,jt->g,modulo,pimod),it->u));
3402 	++it; ++jt;
3403 	continue;
3404       }
3405       if (it->u<jt->u){
3406 	q.push_back(T_unsigned<gen,hashgcd_U>(ichinrem(0,jt->g,modulo,pimod),jt->u));
3407 	++jt;
3408       }
3409       else {
3410 	q.push_back(T_unsigned<gen,hashgcd_U>(ichinrem(it->g,zero,modulo,pimod),it->u));
3411 	++it;
3412       }
3413     }
3414     for (;it!=itend;++it)
3415       q.push_back(T_unsigned<gen,hashgcd_U>(ichinrem(it->g,zero,modulo,pimod),it->u));
3416     for (;jt!=jtend;++jt)
3417       q.push_back(T_unsigned<gen,hashgcd_U>(ichinrem(0,jt->g,modulo,pimod),jt->u));
3418     swap(p,q);
3419   }
3420 
complex_ichinrem(const vector<T_unsigned<int,hashgcd_U>> & p1,const vector<T_unsigned<int,hashgcd_U>> & p2,int i,int modulo,vector<T_unsigned<gen,hashgcd_U>> & p,const gen & pimod)3421   static void complex_ichinrem(const vector< T_unsigned<int,hashgcd_U> > & p1,const vector< T_unsigned<int,hashgcd_U> > & p2,int i,int modulo,vector< T_unsigned<gen,hashgcd_U> > & p,const gen & pimod){
3422     vector< T_unsigned<gen,hashgcd_U> > p_orig,q;
3423     complex_unmod(p1,p2,p_orig,i,modulo);
3424     ichinrem(p_orig,modulo,p,pimod);
3425   }
3426 
complex_ichinrem_ext(const vector<T_unsigned<vecteur,hashgcd_U>> & p1,const vector<T_unsigned<vecteur,hashgcd_U>> & p2,int i,int modulo,vector<T_unsigned<gen,hashgcd_U>> & p,const gen & pimod)3427   static void complex_ichinrem_ext(const vector< T_unsigned<vecteur,hashgcd_U> > & p1,const vector< T_unsigned<vecteur,hashgcd_U> > & p2,int i,int modulo,vector< T_unsigned<gen,hashgcd_U> > & p,const gen & pimod){
3428     vector< T_unsigned<gen,hashgcd_U> > p_orig;
3429     complex_unmod_ext(p1,p2,p_orig,i,modulo);
3430     ichinrem(p_orig,modulo,p,pimod);
3431   }
3432 
max(const vector<T_unsigned<gen,hashgcd_U>> & p,GIAC_CONTEXT)3433   static gen max(const vector< T_unsigned<gen,hashgcd_U> > & p,GIAC_CONTEXT){
3434     vector< T_unsigned<gen,hashgcd_U> >::const_iterator jt=p.begin(),jtend=p.end();
3435     gen g,res;
3436     for (;jt!=jtend;++jt){
3437       g=abs(jt->g,contextptr);
3438       if (is_strictly_greater(g,res,contextptr))
3439 	res=g;
3440     }
3441     return res;
3442   }
3443 
3444   // if res==0 set res to gcd of coeffs of p
3445   // if divide, divide p by res
ppz(vector<T_unsigned<gen,hashgcd_U>> & p,const gen & pgcd,bool divide)3446   static gen ppz(vector< T_unsigned<gen,hashgcd_U> > & p,const gen & pgcd,bool divide){
3447     vector< T_unsigned<gen,hashgcd_U> >::iterator jt=p.begin(),jtend=p.end();
3448     gen res=pgcd;
3449     if (res==0){
3450       for (;jt!=jtend;++jt){
3451 	if (jt->g.type==_VECT){
3452 	  const_iterateur it=jt->g._VECTptr->begin(),itend=jt->g._VECTptr->end();
3453 	  for (;it!=itend;++it){
3454 	    res=gcd(res,*it,context0);
3455 	  }
3456 	}
3457 	else
3458 	  res=gcd(res,jt->g,context0);
3459 	if (is_one(res))
3460 	  return res;
3461       }
3462     }
3463     if (!divide)
3464       return res;
3465     for (jt=p.begin();jt!=jtend;++jt){
3466       jt->g = jt->g/res;
3467     }
3468     return res;
3469   }
3470 
lcmdeno(vector<T_unsigned<gen,hashgcd_U>> & p)3471   static gen lcmdeno(vector< T_unsigned<gen,hashgcd_U> > & p){
3472     vector< T_unsigned<gen,hashgcd_U> >::iterator jt=p.begin(),jtend=p.end();
3473     gen res=1;
3474     for (;jt!=jtend;++jt){
3475       if (jt->g.type==_FRAC){
3476 	res=lcm(res,jt->g._FRACptr->den);
3477 	continue;
3478       }
3479       if (jt->g.type==_VECT){
3480 	const_iterateur it=jt->g._VECTptr->begin(),itend=jt->g._VECTptr->end();
3481 	for (;it!=itend;++it){
3482 	  if (it->type==_FRAC)
3483 	    res=lcm(res,it->_FRACptr->den);
3484 	  if (is_undef(res))
3485 	    return res;
3486 	  if (it->type==_POLY){
3487 	    vector< monomial<gen> >::const_iterator kt=it->_POLYptr->coord.begin(),ktend=it->_POLYptr->coord.end();
3488 	    for (;kt!=ktend;++kt){
3489 	      if (kt->value.type==_FRAC)
3490 		res=lcm(res,kt->value._FRACptr->den);
3491 	    }
3492 	  }
3493 	}
3494 	continue;
3495       }
3496       if (jt->g.type==_POLY){
3497 	vector< monomial<gen> >::const_iterator it=jt->g._POLYptr->coord.begin(),itend=jt->g._POLYptr->coord.end();
3498 	for (;it!=itend;++it){
3499 	  if (it->value.type==_FRAC)
3500 	    res=lcm(res,it->value._FRACptr->den);
3501 	}
3502 	continue;
3503       }
3504     }
3505     if (is_one(res))
3506       return res;
3507     for (jt=p.begin();jt!=jtend;++jt){
3508       jt->g = jt->g * res;
3509     }
3510     return res;
3511   }
3512 
3513   // 1: integer, 2: gaussian integer, 3: ext, 4: ext with gaussint coeff, 0: other
is_integer(const vector<T_unsigned<gen,hashgcd_U>> & p,gen & coefft)3514   static int is_integer(const vector< T_unsigned<gen,hashgcd_U> > & p,gen & coefft){
3515     vector< T_unsigned<gen,hashgcd_U> >::const_iterator jt=p.begin(),jtend=p.end();
3516     int t=1;
3517     for (;jt!=jtend;++jt){
3518       if (jt->g.is_integer())
3519 	continue;
3520       if (jt->g.type==_EXT){
3521 	if (t<3)
3522 	  t=t==1?3:4;
3523 	if (coefft.type==_EXT){
3524 	  if (*(coefft._EXTptr+1)!=*(jt->g._EXTptr+1))
3525 	    return 0;
3526 	}
3527 	else {
3528 	  coefft=jt->g;
3529 	}
3530 	if (t==3 && !is_zero(im(*jt->g._EXTptr,context0)))
3531 	  t=4;
3532 	continue;
3533       }
3534       if (jt->g.type==_POLY){
3535 	vector< monomial<gen> >::const_iterator it=jt->g._POLYptr->coord.begin(),itend=jt->g._POLYptr->coord.end();
3536 	for (;it!=itend;++it){
3537 	  if (it->value.is_integer())
3538 	    continue;
3539 	  if (!it->value.is_cinteger())
3540 	    return 0;
3541 	  if (t!=3)
3542 	    t=2;
3543 	  else
3544 	    t=4;
3545 	}
3546 	continue;
3547       }
3548       if (!jt->g.is_cinteger())
3549 	return 0;
3550       if (t!=3 && t!=4)
3551 	t=2;
3552       else
3553 	t=4;
3554     }
3555     return t;
3556   }
3557 
3558   // reduce g mod modulo using i as square root of -1
complex_smod(const gen & g,int i,int modulo)3559   static int complex_smod(const gen & g,int i,int modulo){
3560     gen tmp=smod(re(g,context0)+i*im(g,context0),modulo);
3561 #ifndef NO_STDEXCEPT
3562     if (tmp.type!=_INT_)
3563       setsizeerr(gettext("complex_smod"));
3564 #endif
3565     return tmp.val;
3566   }
3567 
complex_smod_ext(const gen & g,int i,int modulo)3568   static gen complex_smod_ext(const gen & g,int i,int modulo){
3569     return smod(re(g,context0)+i*im(g,context0),modulo);
3570   }
3571 
complex_smod(const vector<T_unsigned<gen,hashgcd_U>> & p_orig,int i,int modulo,vector<T_unsigned<int,hashgcd_U>> & p)3572   static void complex_smod(const vector< T_unsigned<gen,hashgcd_U> > & p_orig,int i,int modulo,vector< T_unsigned<int,hashgcd_U> > & p){
3573     vector< T_unsigned<gen,hashgcd_U> >::const_iterator it=p_orig.begin(),itend=p_orig.end();
3574     p.clear();
3575     p.reserve(itend-it);
3576     for (;it!=itend;++it){
3577       p.push_back(T_unsigned<int,hashgcd_U>(complex_smod(it->g,i,modulo),it->u));
3578     }
3579   }
3580 
complex_smod_ext(const vector<T_unsigned<gen,hashgcd_U>> & p_orig,int i,int modulo,vector<T_unsigned<vecteur,hashgcd_U>> & p)3581   static bool complex_smod_ext(const vector< T_unsigned<gen,hashgcd_U> > & p_orig,int i,int modulo,vector< T_unsigned<vecteur,hashgcd_U> > & p){
3582     vector< T_unsigned<gen,hashgcd_U> >::const_iterator it=p_orig.begin(),itend=p_orig.end();
3583     p.clear();
3584     p.reserve(itend-it);
3585     vecteur x;
3586     gen tmp,itg;
3587     const_iterateur vt,vtend;
3588     for (;it!=itend;++it){
3589       x.clear();
3590       if (it->g.type!=_EXT){
3591 	tmp=complex_smod_ext(it->g,i,modulo);
3592 	if (!is_zero(tmp))
3593 	  x.push_back(tmp);
3594       }
3595       else {
3596 	tmp=*it->g._EXTptr;
3597 	if (tmp.type!=_VECT || tmp._VECTptr->empty())
3598 	  return false;
3599 	vt=tmp._VECTptr->begin(),vtend=tmp._VECTptr->end();
3600 	x.reserve(vtend-vt);
3601 	for (;vt!=vtend;++vt){
3602 	  itg=complex_smod_ext(*vt,i,modulo);
3603 	  if (is_zero(itg) && x.empty())
3604 	    continue;
3605 	  x.push_back(itg.val);
3606 	}
3607       }
3608       if (!x.empty())
3609 	p.push_back( T_unsigned<vecteur,hashgcd_U> (x,it->u) );
3610     }
3611     return true;
3612   }
3613 
modsqrtminus1(int modulo)3614   int modsqrtminus1(int modulo){
3615     int i;
3616     for (int j=2;j<modulo;++j){
3617       i=powmod(j,(modulo-1)/4,modulo);
3618       if ((longlong(i)*i)%modulo==modulo-1)
3619 	return i;
3620     }
3621     return 0;
3622   }
3623 
gcd(const vector<T_unsigned<gen,hashgcd_U>> & p_orig,const vector<T_unsigned<gen,hashgcd_U>> & q_orig,vector<T_unsigned<gen,hashgcd_U>> & d,vector<T_unsigned<gen,hashgcd_U>> & pcofactor,vector<T_unsigned<gen,hashgcd_U>> & qcofactor,const std::vector<hashgcd_U> & vars,bool compute_cofactors,int nthreads)3624   bool gcd(const vector< T_unsigned<gen,hashgcd_U> > & p_orig,const vector< T_unsigned<gen,hashgcd_U> > & q_orig,vector< T_unsigned<gen,hashgcd_U> > & d, vector< T_unsigned<gen,hashgcd_U> > & pcofactor, vector< T_unsigned<gen,hashgcd_U> > & qcofactor,const std::vector<hashgcd_U> & vars, bool compute_cofactors,int nthreads){
3625 #ifdef NO_TEMPLATE_MULTGCD
3626     return false;
3627 #else
3628     index_t shift_vars;
3629     gen coefft;
3630     int tp=is_integer(p_orig,coefft),tq=is_integer(q_orig,coefft);
3631     if (
3632 	// tp!=1 || tq!=1
3633 	tp==0 || tq==0
3634 	|| !find_shift(vars,shift_vars)
3635 	)
3636       return false;
3637     bool is_complex=tp==2 || tq==2;
3638     compute_cofactors=true; // FIXME
3639     index_t pdeg,qdeg,pdegmod,qdegmod,gdegmod,gdegmod2,gdeg;
3640     degree(p_orig,shift_vars,pdeg);
3641     degree(q_orig,shift_vars,qdeg);
3642     gdeg=index_min(pdeg,qdeg);
3643     // gen m=30000,pimod=1;
3644     gen m=536871000,pimod=1;
3645     gen lcoeffp=p_orig.front().g,lcoeffq=q_orig.front().g,gcdlcoeff=gcd(lcoeffp,lcoeffq,context0);
3646     d.clear();
3647     pcofactor.clear();
3648     qcofactor.clear();
3649     bool divtest;
3650     vector< vector<int> > pv,qv,dv,dpv,dim2gcdv,dim2pcofactorv,dim2qcofactorv;
3651     if (is_complex){
3652       vector< T_unsigned<int,hashgcd_U> > p1,q1,g1,pcof1,qcof1,p2,q2,g2,pcof2,qcof2;
3653       for (;;){
3654 	m=nextprime(m+1);
3655 #ifdef TIMEOUT
3656 	control_c();
3657 #endif
3658 	if (ctrl_c || interrupted || m.type!=_INT_)
3659 	  return false;
3660 	int modulo=m.val;
3661 	// computing gcd in Z[i]: use a modulo =1[4], find gcd for both roots of -1 mod modulo
3662 	if (modulo%4==3)
3663 	  continue;
3664 	// find square root of -1
3665 	int i=modsqrtminus1(modulo);
3666 	int lg1=complex_smod(gcdlcoeff,i,modulo),lg2=complex_smod(gcdlcoeff,-i,modulo);
3667 	int lp1=complex_smod(lcoeffp,i,modulo),lp2=complex_smod(lcoeffp,-i,modulo);
3668 	int lq1=complex_smod(lcoeffq,i,modulo),lq2=complex_smod(lcoeffq,-i,modulo);
3669 	if (!lg1 || !lp1 || !lq1 || !lg2 || !lp2 || !lq2)
3670 	  continue;
3671 	complex_smod(p_orig,i,modulo,p1);
3672 	degree(p1,shift_vars,pdegmod);
3673 	if (pdegmod!=pdeg)
3674 	  continue;
3675 	complex_smod(q_orig,i,modulo,q1);
3676 	degree(q1,shift_vars,qdegmod);
3677 	if (qdegmod!=qdeg)
3678 	  continue;
3679 	complex_smod(p_orig,-i,modulo,p2);
3680 	degree(p2,shift_vars,pdegmod);
3681 	if (pdegmod!=pdeg)
3682 	  continue;
3683 	complex_smod(q_orig,-i,modulo,q2);
3684 	degree(q2,shift_vars,qdegmod);
3685 	if (qdegmod!=qdeg)
3686 	  continue;
3687 	if (!mod_gcd(p1,q1,modulo,g1,pcof1,qcof1,vars,compute_cofactors,compute_cofactors,divtest,pv,qv,dv,dpv,dim2gcdv,dim2pcofactorv,dim2qcofactorv,nthreads))
3688 	  continue;
3689 	// normalize g, pcof, qcof
3690 	smallmult(smod(longlong(lg1)*invmod(g1.front().g,modulo),modulo),g1,g1,modulo);
3691 	smallmult(smod(longlong(lp1)*invmod(pcof1.front().g,modulo),modulo),pcof1,pcof1,modulo);
3692 	smallmult(smod(longlong(lq1)*invmod(qcof1.front().g,modulo),modulo),qcof1,qcof1,modulo);
3693 	degree(g1,shift_vars,gdegmod);
3694 	if (!mod_gcd(p2,q2,modulo,g2,pcof2,qcof2,vars,compute_cofactors,compute_cofactors,divtest,pv,qv,dv,dpv,dim2gcdv,dim2pcofactorv,dim2qcofactorv,nthreads))
3695 	  continue;
3696 	smallmult(smod(longlong(lg2)*invmod(g2.front().g,modulo),modulo),g2,g2,modulo);
3697 	smallmult(smod(longlong(lp2)*invmod(pcof2.front().g,modulo),modulo),pcof2,pcof2,modulo);
3698 	smallmult(smod(longlong(lq2)*invmod(qcof2.front().g,modulo),modulo),qcof2,qcof2,modulo);
3699 	degree(g2,shift_vars,gdegmod2);
3700 	if (gdegmod2!=gdegmod)
3701 	  continue;
3702 	int cmp=compare(gdegmod,gdeg);
3703 	if (cmp==0){ // bad reduction
3704 	  continue;
3705 	}
3706 	if (cmp==-1){
3707 	  // restart
3708 	  d.clear();
3709 	  pcofactor.clear();
3710 	  qcofactor.clear();
3711 	  pimod=1;
3712 	  continue;
3713 	}
3714 	if (cmp==-2){ // same deg, chinese remainder
3715 	  // same degrees, chinese remainder
3716 	  complex_ichinrem(g1,g2,i,modulo,d,pimod);
3717 	  if (compute_cofactors){
3718 	    complex_ichinrem(pcof1,pcof2,i,modulo,pcofactor,pimod);
3719 	    complex_ichinrem(qcof1,qcof2,i,modulo,qcofactor,pimod);
3720 	  }
3721 	  pimod = modulo * pimod;
3722 	}
3723 	else { // restart with this gcd
3724 	  complex_unmod(g1,g2,d,i,modulo);
3725 	  if (compute_cofactors){
3726 	    complex_unmod(pcof1,pcof2,pcofactor,i,modulo);
3727 	    complex_unmod(qcof1,qcof2,qcofactor,i,modulo);
3728 	  }
3729 	  pimod=modulo;
3730 	  gdeg=gdegmod;
3731 	}
3732 	// finished??
3733 	if (compute_cofactors){
3734 	  // d*pcofactor=p_orig*gcdlcoeff mod pimod
3735 	  // if |gcdlcoeff*p_orig|+|g|*|pcof|*min(size(g),size(pcof))< pimod we are done
3736 	  int mgp=int(std::min(d.size(),pcofactor.size()));
3737 	  int mgq=int(std::min(d.size(),qcofactor.size()));
3738 	  gen maxg=max(d,context0),maxp=max(p_orig,context0),maxq=max(q_orig,context0),maxpcof=max(pcofactor,context0),maxqcof=max(qcofactor,context0);
3739 	  gen dz=ppz(d,0,false),pz=ppz(pcofactor,0,false),qz=ppz(qcofactor,0,false);
3740 	  maxg = maxg/abs(dz,context0);
3741 	  maxpcof = maxpcof/abs(pz,context0);
3742 	  maxqcof = maxqcof/abs(qz,context0);
3743 	  if (is_strictly_greater(pimod,abs(gcdlcoeff,context0)*maxp+mgp*maxg*maxpcof,context0) && is_strictly_greater(pimod,abs(gcdlcoeff,context0)*maxq+mgq*maxg*maxqcof,context0) ){
3744 	    // divide g,pcofactor,qcofactor by their integer content
3745 	    ppz(d,dz,true);
3746 	    if (compute_cofactors){
3747 	      ppz(pcofactor,pz,true);
3748 	      ppz(qcofactor,qz,true);
3749 	    }
3750 	    return true;
3751 	  }
3752 	}
3753 	if (divtest) {
3754 	  // division test
3755 	  vector< T_unsigned<gen,hashgcd_U> > dtest(d),pquo,qquo,rem;
3756 	  ppz(d,0,true);
3757 	  if (hashdivrem(p_orig,dtest,pquo,rem,vars,0 /* reduce */,0/*qmax*/,false)==1 && rem.empty()){
3758 	    if (hashdivrem(q_orig,dtest,qquo,rem,vars,0 /* reduce */,0/*qmax*/,false)==1 && rem.empty()){
3759 	      pcofactor=pquo;
3760 	      qcofactor=qquo;
3761 	      return true;
3762 	    }
3763 	  }
3764 	  d=dtest;
3765 	}
3766       } // end for (;;)
3767       return false;
3768     } // end if (is_complex)
3769     // gcd in Z[x1,..,xn]
3770     vector< T_unsigned<int,hashgcd_U> > p,q,g,pcof,qcof;
3771     for (;;){
3772       m=nextprime(m+1);
3773 #ifdef TIMEOUT
3774       control_c();
3775 #endif
3776       if (ctrl_c || interrupted || m.type!=_INT_)
3777 	return false;
3778       int modulo=m.val;
3779       int lg=smod(gcdlcoeff,modulo).val,lp=smod(lcoeffp,modulo).val,lq=smod(lcoeffq,modulo).val;
3780       if (!lg || !lp || !lq)
3781 	continue;
3782       smod(p_orig,modulo,p);
3783       degree(p,shift_vars,pdegmod);
3784       if (pdegmod!=pdeg)
3785 	continue;
3786       smod(q_orig,modulo,q);
3787       degree(q,shift_vars,qdegmod);
3788       if (qdegmod!=qdeg)
3789 	continue;
3790       if (!mod_gcd(p,q,modulo,g,pcof,qcof,vars,compute_cofactors,compute_cofactors,divtest,pv,qv,dv,dpv,dim2gcdv,dim2pcofactorv,dim2qcofactorv,nthreads))
3791 	continue;
3792       degree(g,shift_vars,gdegmod);
3793       // normalize g, pcof, qcof
3794       smallmult(smod(longlong(lg)*invmod(g.front().g,modulo),modulo),g,g,modulo);
3795       smallmult(smod(longlong(lp)*invmod(pcof.front().g,modulo),modulo),pcof,pcof,modulo);
3796       smallmult(smod(longlong(lq)*invmod(qcof.front().g,modulo),modulo),qcof,qcof,modulo);
3797       // CERR << " g " << g << " pcof " << pcof << "qcof " << qcof << '\n';
3798       int cmp=compare(gdegmod,gdeg);
3799       if (cmp==0){ // bad reduction
3800 	continue;
3801       }
3802       if (cmp==-1){
3803 	// restart
3804 	d.clear();
3805 	pcofactor.clear();
3806 	qcofactor.clear();
3807 	pimod=1;
3808 	continue;
3809       }
3810       if (cmp==-2){
3811 	// same degrees, chinese remainder
3812 	ichinrem(g,modulo,d,pimod);
3813 	if (compute_cofactors){
3814 	  ichinrem(pcof,modulo,pcofactor,pimod);
3815 	  ichinrem(qcof,modulo,qcofactor,pimod);
3816 	}
3817 	pimod = modulo * pimod;
3818       }
3819       else {
3820 	// restart with this modular gcd
3821 	unmod(g,d,modulo);
3822 	if (compute_cofactors){
3823 	  unmod(pcof,pcofactor,modulo);
3824 	  unmod(qcof,qcofactor,modulo);
3825 	}
3826 	pimod=modulo;
3827 	gdeg=gdegmod;
3828       }
3829       // are we finished?
3830       if (compute_cofactors){
3831 	// d*pcofactor=p_orig*gcdlcoeff mod pimod
3832 	// if |gcdlcoeff*p_orig|+|g|*|pcof|*min(size(g),size(pcof))< pimod we are done
3833 	int mgp=int(std::min(d.size(),pcofactor.size()));
3834 	int mgq = int(std::min(d.size(), qcofactor.size()));
3835 	gen maxg=max(d,context0),maxp=max(p_orig,context0),maxq=max(q_orig,context0),maxpcof=max(pcofactor,context0),maxqcof=max(qcofactor,context0);
3836 	gen dz=ppz(d,0,false),pz=ppz(pcofactor,0,false),qz=ppz(qcofactor,0,false);
3837 	maxg = maxg/ dz;
3838 	maxpcof = maxpcof/pz;
3839 	maxqcof = maxqcof/qz;
3840 	if (is_strictly_greater(pimod,abs(gcdlcoeff,context0)*maxp+mgp*maxg*maxpcof,context0) && is_strictly_greater(pimod,abs(gcdlcoeff,context0)*maxq+mgq*maxg*maxqcof,context0) ){
3841 	  // divide g,pcofactor,qcofactor by their integer content
3842 	  ppz(d,dz,true);
3843 	  if (compute_cofactors){
3844 	    ppz(pcofactor,pz,true);
3845 	    ppz(qcofactor,qz,true);
3846 	  }
3847 	  return true;
3848 	}
3849       }
3850       if (divtest) {
3851 	// division test
3852 	vector< T_unsigned<gen,hashgcd_U> > dtest(d),pquo,qquo,rem;
3853 	ppz(d,0,true);
3854 	if (hashdivrem(p_orig,dtest,pquo,rem,vars,0 /* reduce */,0/*qmax*/,false)==1 && rem.empty()){
3855 	  if (hashdivrem(q_orig,dtest,qquo,rem,vars,0 /* reduce */,0/*qmax*/,false)==1 && rem.empty()){
3856 	    pcofactor=pquo;
3857 	    qcofactor=qquo;
3858 	    return true;
3859 	  }
3860 	}
3861 	d=dtest;
3862       }
3863     }
3864 #endif // NO_TEMPLATE_MULTGCD
3865   }
3866 
3867   /* *************************************************
3868            MODULAR ALGEBRAIC EXTENSIONS GCD
3869      ************************************************* */
3870   // Beware: overflow may occur if INT128 not defined
3871   // if min(degree)*modulo^2>=2^63
mulsmall(const vector<int>::const_iterator & ita0,const vector<int>::const_iterator & ita_end,const vector<int>::const_iterator & itb0,const vector<int>::const_iterator & itb_end,int modulo,vector<int> & new_coord)3872   void mulsmall(const vector<int>::const_iterator & ita0,const vector<int>::const_iterator & ita_end,const vector<int>::const_iterator & itb0,const vector<int>::const_iterator & itb_end,int modulo,vector<int> & new_coord){
3873     new_coord.clear();
3874     if (ita0==ita_end || itb0==itb_end)
3875       return;
3876     new_coord.reserve((ita_end-ita0)+(itb_end-itb0)-1);
3877     vector<int>::const_iterator ita_begin=ita0,ita=ita0,itb=itb0;
3878 #ifdef INT128
3879     if ( giacmin(itb_end-itb0,ita_end-ita0)*double(modulo)*modulo >= (1ULL<<63) ){
3880       for ( ; ita!=ita_end; ++ita ){
3881 	vector<int>::const_iterator ita_cur=ita,itb_cur=itb;
3882 	int128_t res=0;
3883 	for (;itb_cur!=itb_end;--ita_cur,++itb_cur) {
3884 	  res += longlong(*ita_cur) * *itb_cur ;
3885 	  if (ita_cur==ita_begin)
3886 	    break;
3887 	}
3888 	int R=res%modulo;
3889 	R += (unsigned(R)>>31)*modulo; // make positive
3890 	R -= (unsigned((modulo>>1)-R)>>31)*modulo;
3891 	new_coord.push_back(R);// smod(R,modulo);
3892       }
3893       --ita;
3894       ++itb;
3895       for ( ; itb!=itb_end;++itb){
3896 	int128_t res=0;
3897 	vector<int>::const_iterator ita_cur=ita,itb_cur=itb;
3898 	for (;;) {
3899 	  res += longlong(*ita_cur) * *itb_cur ;
3900 	  ++itb_cur;
3901 	  if (ita_cur==ita_begin || itb_cur==itb_end)
3902 	    break;
3903 	  --ita_cur;
3904 	}
3905 	int R=res%modulo;
3906 	R += (unsigned(R)>>31)*modulo; // make positive
3907 	R -= (unsigned((modulo>>1)-R)>>31)*modulo;
3908 	new_coord.push_back(R);// smod(R,modulo);
3909       }
3910       return;
3911     }
3912 #endif
3913     for ( ; ita!=ita_end; ++ita ){
3914       vector<int>::const_iterator ita_cur=ita,itb_cur=itb;
3915       longlong res=0;
3916       for (;itb_cur!=itb_end;--ita_cur,++itb_cur) {
3917 	res += longlong(*ita_cur) * *itb_cur ;
3918 	if (ita_cur==ita_begin)
3919 	  break;
3920       }
3921       new_coord.push_back(smod(res,modulo));
3922     }
3923     --ita;
3924     ++itb;
3925     for ( ; itb!=itb_end;++itb){
3926       longlong res=0;
3927       vector<int>::const_iterator ita_cur=ita,itb_cur=itb;
3928       for (;;) {
3929 	res += longlong(*ita_cur) * *itb_cur ;
3930 	++itb_cur;
3931 	if (ita_cur==ita_begin || itb_cur==itb_end)
3932 	  break;
3933 	--ita_cur;
3934       }
3935       new_coord.push_back(smod(res,modulo));
3936     }
3937   }
3938 
3939   // res=a*b mod pmin,modulo
mulext(const vector<int> & a,const vector<int> & b,const vector<int> & pmin,int modulo,vector<int> & res)3940   void mulext(const vector<int> & a,const vector<int> & b,const vector<int> & pmin,int modulo,vector<int> & res){
3941     if (b.empty()){
3942       res.clear();
3943       return;
3944     }
3945     if (b.size()==1 && b.front()==1){
3946       res=a;
3947       return;
3948     }
3949     vector<int> q,tmp;
3950     mulsmall(a.begin(),a.end(),b.begin(),b.end(),modulo,tmp);
3951     DivRem(tmp,pmin,modulo,q,res);
3952   }
3953 
3954   // res=a*b mod pmin,modulo with temporary passed as arg
mulext(const vector<int> & a,const vector<int> & b,const vector<int> & pmin,int modulo,vector<int> & res,vector<int> & tmp,vector<int> & q)3955   static void mulext(const vector<int> & a,const vector<int> & b,const vector<int> & pmin,int modulo,vector<int> & res,vector<int> & tmp,vector<int> & q){
3956     if (b.empty()){
3957       res.clear();
3958       return;
3959     }
3960     if (b.size()==1 && b.front()==1){
3961       res=a;
3962       return;
3963     }
3964     mulsmall(a.begin(),a.end(),b.begin(),b.end(),modulo,tmp);
3965     DivRem(tmp,pmin,modulo,q,res);
3966   }
3967 
mulextaux2(const gen & a,const gen & b,int modulo)3968   static gen mulextaux2(const gen & a,const gen & b,int modulo){
3969     gen res= a*b;
3970     if (res.type==_FRAC)
3971       return smod(res,modulo);
3972     else
3973       return res;
3974   }
3975 
mulextaux(const modpoly & a,const modpoly & b,int modulo,modpoly & new_coord)3976   static void mulextaux(const modpoly & a,const modpoly &b,int modulo,modpoly & new_coord){
3977 #ifdef TIMEOUT
3978     control_c();
3979 #endif
3980     if (ctrl_c || interrupted) {
3981       interrupted = true; ctrl_c=false;
3982       new_coord=vecteur(1, gensizeerr(gettext("Stopped by user interruption.")));
3983       return;
3984     }
3985     modpoly::const_iterator ita=a.begin(),ita_end=a.end(),itb=b.begin(),itb_end=b.end();
3986     new_coord.clear();
3987     ita=a.begin(); itb=b.begin();
3988     if (ita==ita_end || itb==itb_end)
3989       return;
3990     modpoly::const_iterator ita_begin=ita;
3991     for ( ; ita!=ita_end; ++ita ){
3992       modpoly::const_iterator ita_cur=ita,itb_cur=itb;
3993       gen res;
3994       for (;;) {
3995 	res += mulextaux2(*ita_cur,*itb_cur,modulo); // res = res + (*ita_cur) * (*itb_cur);
3996 	if (ita_cur==ita_begin)
3997 	  break;
3998 	--ita_cur;
3999 	++itb_cur;
4000 	if (itb_cur==itb_end)
4001 	  break;
4002       }
4003       new_coord.push_back(res);
4004     }
4005     --ita;
4006     ++itb;
4007     for ( ; itb!=itb_end;++itb){
4008       modpoly::const_iterator ita_cur=ita,itb_cur=itb;
4009       gen res;
4010       for (;;) {
4011 	res += mulextaux2(*ita_cur,*itb_cur,modulo); // res = res + (*ita_cur) * (*itb_cur);
4012 	if (ita_cur==ita_begin)
4013 	  break;
4014 	--ita_cur;
4015 	++itb_cur;
4016 	if (itb_cur==itb_end)
4017 	  break;
4018       }
4019       new_coord.push_back(res);
4020     }
4021   }
4022 
mulext(const vecteur & a,const vecteur & b,const vecteur & pmin,int modulo,vecteur & res)4023   static void mulext(const vecteur & a,const vecteur & b,const vecteur & pmin,int modulo,vecteur & res){
4024     if (b.empty()){
4025       res.clear();
4026       return;
4027     }
4028     if (b.size()==1 && b.front()==1){
4029       res=a;
4030       return;
4031     }
4032     vecteur q,tmp;
4033     environment env;
4034     env.modulo=modulo;
4035     env.moduloon=true;
4036     mulextaux(a,b,modulo,tmp);
4037     // operator_times(a,b,0,tmp); // bug if a and b contains fraction
4038     DivRem(tmp,pmin,&env,q,res);
4039   }
4040 
4041   // a *=b mod pmin, modulo
mulext(vector<int> & a,const vector<int> & b,const vector<int> & pmin,int modulo)4042   void mulext(vector<int> & a,const vector<int> & b,const vector<int> & pmin,int modulo){
4043     if (b.empty()){
4044       a.clear();
4045       return;
4046     }
4047     if (b.size()==1 && b.front()==1)
4048       return;
4049     vector<int> q,tmp;
4050     mulsmall(a.begin(),a.end(),b.begin(),b.end(),modulo,tmp);
4051     DivRem(tmp,pmin,modulo,q,a);
4052   }
4053 
mulext(vector<vector<int>> & a,const vector<int> & b,const vector<int> & pmin,int modulo,vector<int> & tmp,vector<int> & q)4054   static void mulext(vector< vector<int> > & a,const vector<int> & b,const vector<int> & pmin,int modulo,vector<int> & tmp,vector<int> & q){
4055     if (b.empty()){
4056       a.clear();
4057       return;
4058     }
4059     if (b.size()==1 && b.front()==1)
4060       return;
4061     vector< vector<int> >::iterator it=a.begin(),itend=a.end();
4062     for (;it!=itend;++it){
4063       mulsmall(it->begin(),it->end(),b.begin(),b.end(),modulo,tmp);
4064       DivRem(tmp,pmin,modulo,q,*it);
4065     }
4066   }
4067 
4068   // inverse of rootof(a:pmin) modulo
4069   // pmin=1*pmin+0*a
4070   // a_=0*a+1*b
4071   // ...
4072   // 1=?*a+ainv*b
invmodext_(const vector<int> & a_,const vector<int> & pmin,int modulo,vector<int> & u0,vector<int> & a,vector<int> & b,vector<int> & q,vector<int> & r,vector<int> & u1,vector<int> & u2)4073   static bool invmodext_(const vector<int> & a_,const vector<int> & pmin,int modulo,vector<int> & u0,vector<int> &a,vector<int> & b,vector<int> &q,vector<int> &r,vector<int> &u1,vector<int> & u2){
4074     if (a_.empty())
4075       return false;
4076     if (a_.size()==1){
4077       if (gcd(modulo,a_[0])!=1)
4078 	return false;
4079       u0.resize(1);
4080       u0[0]=invmod(a_[0],modulo);
4081       return true;
4082     }
4083     if (debug_infolevel>10)
4084       CERR << a_ << " inv " << pmin << " mod " << modulo << '\n';
4085     a=pmin;
4086     b=a_;
4087     vector<int>::iterator it,itend;
4088     u0.clear();
4089     u1.push_back(1);
4090     for (;!b.empty();){
4091       if (gcd(modulo,b.front())!=1)
4092 	return false;
4093       DivRem(a,b,modulo,q,r);
4094       swap(a,b); // a,b,r -> b,a,r
4095       swap(b,r); // -> b,r,a
4096       // u2=u0-q*u1 modulo
4097       mulext(q,u1,pmin,modulo,u2); // u2=q*u1
4098       submod(u2,u0,modulo); // u2=q*u1-u0
4099       for (it=u2.begin(),itend=u2.end();it!=itend;++it)
4100 	*it = -*it; // done
4101       swap(u0,u1);
4102       swap(u1,u2);
4103       if (debug_infolevel>10)
4104 	CERR << a << "  " << b << " " << u0 << " " << u1 << '\n';
4105     }
4106     if (gcd(modulo,a.front())!=1 || u0.empty())
4107       return false;
4108     mulmod(u0,invmod(a.front(),modulo),modulo);
4109     return true;
4110   }
invmodext(const vector<int> & a_,const vector<int> & pmin,int modulo,vector<int> & u0)4111   bool invmodext(const vector<int> & a_,const vector<int> & pmin,int modulo,vector<int> & u0){
4112     vector<int> a,b,q,r,u1,u2; // u0=ainv
4113     return invmodext_(a_,pmin,modulo,u0,a,b,q,r,u1,u2);
4114   }
4115 
invmod(const vector<int> & a,const modred & R)4116   static vector<int> invmod(const vector<int> & a,const modred & R){
4117     vector<int> ainv;
4118     if (!invmodext(a,R.pmin,R.modulo,ainv)){
4119 #ifndef NO_STDEXCEPT
4120       setsizeerr(gettext("invmodext"));
4121 #endif
4122       ainv.clear();
4123     }
4124     return ainv;
4125   }
4126 
4127   // c = a*b % reduce
type_operator_reduce(const vector<int> & a,const vector<int> & b,vector<int> & c,const modred & reduce)4128   static void type_operator_reduce(const vector<int> & a,const vector<int> & b,vector<int> & c,const modred & reduce){
4129     mulext(a,b,reduce.pmin,reduce.modulo,c);
4130   }
4131 
operator %(const vector<int> & a,const modred & reduce)4132   vector<int> operator %(const vector<int> & a,const modred & reduce){
4133     vector<int> q,res;
4134     DivRem(a,reduce.pmin,reduce.modulo,q,res);
4135     return res;
4136   }
4137 
4138   // c += a*b % reduce
type_operator_plus_times_reduce(const vector<int> & a,const vector<int> & b,vector<int> & c,const modred & reduce)4139   static void type_operator_plus_times_reduce(const vector<int> & a,const vector<int> & b,vector<int> & c,const modred & reduce){
4140     vector<int> tmp;
4141     mulext(a,b,reduce.pmin,reduce.modulo,tmp);
4142     addmod(c,tmp,reduce.modulo);
4143   }
4144 
invmod(const vecteur & a,const Modred & R)4145   static vecteur invmod(const vecteur & a,const Modred & R){
4146     if (a.size()==1)
4147       return vecteur(1,invmod(a.front(),R.modulo));
4148     // should not occur if division test is done with lcoeff=1
4149     vecteur ainv,v,d;
4150     environment env;
4151     env.modulo=R.modulo;
4152     env.moduloon=true;
4153     egcd(a,R.pmin,&env,ainv,v,d);
4154     if (d.size()!=1){
4155 #ifndef NO_STDEXCEPT
4156       setsizeerr(gettext("invmodext"));
4157 #endif
4158       return vecteur(1,gensizeerr(gettext("invmodext")));
4159     }
4160     return ainv;
4161   }
4162 
4163   // c = a*b % reduce
type_operator_reduce(const vecteur & a,const vecteur & b,vecteur & c,const Modred & reduce)4164   static void type_operator_reduce(const vecteur & a,const vecteur & b,vecteur & c,const Modred & reduce){
4165     mulext(a,b,reduce.pmin,reduce.modulo,c);
4166   }
4167 
type_operator_times(const vecteur & a,const vecteur & b,vecteur & c)4168   static void type_operator_times(const vecteur & a,const vecteur &b,vecteur & c){
4169     mulmodpoly(a,b,c);
4170   }
4171 
type_operator_plus_times(const vecteur & a,const vecteur & b,vecteur & c)4172   static void type_operator_plus_times(const vecteur & a,const vecteur & b,vecteur & c){
4173     vecteur tmp;
4174     mulmodpoly(a,b,tmp);
4175     addmodpoly(c,tmp,c);
4176   }
4177 
type_operator_plus_times_reduce(const vecteur & a,const vecteur & b,vecteur & c,int reduce)4178   static void type_operator_plus_times_reduce(const vecteur & a,const vecteur & b,vecteur & c,int reduce){
4179     assert(reduce==0);
4180     vecteur tmp;
4181     mulmodpoly(a,b,tmp);
4182     addmodpoly(c,tmp,c);
4183   }
4184 
4185   // c += a*b % reduce
type_operator_plus_times_reduce(const vecteur & a,const vecteur & b,vecteur & c,const Modred & reduce)4186   static void type_operator_plus_times_reduce(const vecteur & a,const vecteur & b,vecteur & c,const Modred & reduce){
4187     vecteur tmp;
4188     mulext(a,b,reduce.pmin,reduce.modulo,tmp);
4189     addmod(c,tmp,reduce.modulo);
4190   }
4191 
operator %(const vecteur & a,const Modred & reduce)4192   vecteur operator %(const vecteur & a,const Modred & reduce){
4193     vecteur q,res;
4194     environment env;
4195     env.modulo=reduce.modulo;
4196     env.moduloon=true;
4197     DivRem(a,reduce.pmin,&env,q,res);
4198     return res;
4199   }
4200 
smallmult(int g,const std::vector<T_unsigned<vector<int>,hashgcd_U>> & v1,std::vector<T_unsigned<vector<int>,hashgcd_U>> & v,int reduce)4201   static void smallmult(int g,const std::vector< T_unsigned<vector<int>,hashgcd_U> > & v1,std::vector< T_unsigned<vector<int>,hashgcd_U> > & v,int reduce){
4202     if (!g){
4203       v.clear();
4204       return;
4205     }
4206     std::vector< T_unsigned<vector<int>,hashgcd_U> >::const_iterator it1=v1.begin(),it1end=v1.end();
4207     if (&v1==&v){
4208       std::vector< T_unsigned<vector<int>,hashgcd_U> >::iterator it1=v.begin(),it1end=v.end();
4209       for (;it1!=it1end;++it1){
4210 	mulmod(g,it1->g,reduce);
4211 	// it1->g = (g*it1->g) % reduce;
4212       }
4213     }
4214     else {
4215       v.clear();
4216       v.reserve(it1end-it1); // worst case
4217       vector<int> res;
4218       for (;it1!=it1end;++it1){
4219 	res=it1->g;
4220 	mulmod(g,res,reduce);
4221 	v.push_back(T_unsigned<vector<int>,hashgcd_U>(res,it1->u));
4222       }
4223     }
4224   }
4225 
4226   // a=b*q+r, modifies b (multiplication by inverse of lcoeff)
4227   // if you want q corresponding to original b, set q_orig_b to true
divrem_(vector<vector<int>> & a,vector<vector<int>> & b,const vector<int> & pmin,int modulo,vector<vector<int>> * qptr,bool set_q_orig_b,vector<int> & b0,vector<int> & b0inv,vector<int> & tmp,vector<int> & tmp1,vector<int> & tmp2,vector<int> & tmp3,vector<int> & tmp4,vector<int> & tmp5)4228   static bool divrem_(vector< vector<int> > & a,vector< vector<int> > & b,const vector<int> & pmin, int modulo, vector< vector<int> > * qptr,bool set_q_orig_b,vector<int> & b0,vector<int> & b0inv,vector<int> & tmp,vector<int> & tmp1,vector<int> & tmp2,vector<int> & tmp3,vector<int> & tmp4,vector<int> & tmp5){
4229     int as=int(a.size()),bs=int(b.size());
4230     if (!bs)
4231       return false;
4232     if (set_q_orig_b)
4233       b0=b.front();
4234     if (!invmodext_(b.front(),pmin,modulo,b0inv,tmp,tmp1,tmp2,tmp3,tmp4,tmp5))
4235       return false;
4236     if (qptr)
4237       qptr->clear();
4238     if (as<bs)
4239       return true;
4240     if (bs==1){
4241       if (qptr){
4242 	swap(*qptr,a);
4243 	if (set_q_orig_b)
4244 	  mulext(*qptr,b0inv,pmin,modulo,tmp1,tmp2);
4245       }
4246       a.clear();
4247       return true;
4248     }
4249     mulext(b,b0inv,pmin,modulo,tmp1,tmp2);
4250     vector< vector<int> >::iterator it,jt,jtend=b.end();
4251     int nstep=as-bs+1,pos=0;
4252 #if 0
4253     if (nstep==2){ // normal remainder sequence
4254       // compute quotient from a[0], a[1] and b[0]==1 b[1]
4255       // x coeff of q is q1=a[0], cst coeff of q is q0=a[1]-a[0]*b[1]
4256       // a -= q*b
4257       // x^k coeff ak -> ak- q0*bk - q1*bk-1, but beware a[0]==lcoeff(a)
4258       // a[k] = a[k]- (q1*b[k] + q0*b[k-1])
4259       mulext(a[0],b[1],pmin,modulo,tmp,tmp1,tmp2);
4260       submod(a[1],tmp,modulo); // store q0 in a[1] (a[1] not used anymore)
4261       for (int k=2;k<a.size();++k){
4262 	submulext(a[k],a[0],b[k],a[1],b[k-1],pmin,modulo);
4263       }
4264       pos=2;
4265     }
4266 #endif
4267     for (;pos<nstep;++pos){
4268       vector<int> & q = a[pos];
4269       if (qptr){
4270 	if (set_q_orig_b){
4271 	  mulext(q,b0inv,pmin,modulo,tmp,tmp1,tmp2);
4272 	  qptr->push_back(tmp);
4273 	}
4274 	else
4275 	  qptr->push_back(q);
4276       }
4277       if (!q.empty()){
4278 	for (it=a.begin()+pos+1,jt=b.begin()+1;jt!=jtend;++it,++jt){
4279 	  mulext(*jt,q,pmin,modulo,tmp,tmp1,tmp2);
4280 	  submod(*it,tmp,modulo);
4281 	}
4282       }
4283     }
4284     while (pos<as && a[pos].empty())
4285       ++pos;
4286     a.erase(a.begin(),a.begin()+pos);
4287     if (set_q_orig_b)
4288       mulext(b,b0,pmin,modulo,tmp1,tmp2);
4289     return true;
4290   }
4291 
4292   // find gcd of p and q modulo pmin,modulo
4293   // answer in d
4294   // return false if one of the lcoeff if not invertible during Euclide's algorithm
gcdsmallmodpoly_ext(const vector<vector<int>> & p,const vector<vector<int>> & q,const vector<int> & pmin,int modulo,vector<vector<int>> & d)4295   static bool gcdsmallmodpoly_ext(const vector< vector<int> > & p,const vector< vector<int> > & q,const vector<int> & pmin,int modulo,vector< vector<int> > & d){
4296     // lcoeffs of p/q should be invertible mod modulo
4297     // for q this is checked at the first divrem
4298     if (p.empty()){
4299       d=q;
4300       return true;
4301     }
4302     if (q.empty()){
4303       d=p;
4304       return true;
4305     }
4306     vector<int> p0inv,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7,tmp8;
4307     if (!invmodext(p.front(),pmin,modulo,p0inv))
4308       return false;
4309     d=p;
4310     vector< vector<int> > b(q);
4311     for (;!b.empty();){
4312       if (!divrem_(d,b,pmin,modulo,0,false,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7,tmp8))
4313 	return false;
4314       swap(d,b);
4315     }
4316     if (!invmodext(d.front(),pmin,modulo,p0inv))
4317       return false;
4318     mulext(d,p0inv,pmin,modulo,tmp1,tmp2);
4319     return true;
4320   }
4321 
smod_ext(const vector<T_unsigned<gen,hashgcd_U>> & p_orig,int modulo,vector<T_unsigned<vecteur,hashgcd_U>> & p)4322   static bool smod_ext(const vector< T_unsigned<gen,hashgcd_U> > & p_orig,int modulo,vector< T_unsigned<vecteur,hashgcd_U> > & p){
4323     p.clear();
4324     vector< T_unsigned<gen,hashgcd_U> >::const_iterator it=p_orig.begin(),itend=p_orig.end();
4325     p.reserve(itend-it);
4326     vecteur x;
4327     gen tmp,itg;
4328     const_iterateur vt,vtend;
4329     for (;it!=itend;++it){
4330       x.clear();
4331       if (it->g.type!=_EXT){
4332 	tmp=smod(it->g,modulo);
4333 	if (!is_zero(tmp))
4334 	  x.push_back(tmp);
4335       }
4336       else {
4337 	tmp=*it->g._EXTptr;
4338 	if (tmp.type!=_VECT || tmp._VECTptr->empty())
4339 	  return false;
4340 	vt=tmp._VECTptr->begin(),vtend=tmp._VECTptr->end();
4341 	x.reserve(vtend-vt);
4342 	for (;vt!=vtend;++vt){
4343 	  itg=smod(*vt,modulo);
4344 	  if (is_zero(itg) && x.empty())
4345 	    continue;
4346 	  x.push_back(itg);
4347 	}
4348       }
4349       if (!x.empty())
4350 	p.push_back( T_unsigned<vecteur,hashgcd_U> (x,it->u) );
4351     }
4352     return true;
4353   }
4354 
hornermod_ext(const vector<vector<int>> & v,int alpha,int modulo)4355   static vector<int> hornermod_ext(const vector< vector<int> > & v,int alpha,int modulo){
4356     vector< vector<int> >::const_iterator it=v.begin(),itend=v.end();
4357     if (!alpha)
4358       return it==itend?vector<int>(0):v.back();
4359     vector<int> res;
4360     for (;it!=itend;++it){
4361       mulmod(res,alpha,modulo);
4362       addmod(res,*it,modulo);
4363     }
4364     return res;
4365   }
4366 
4367   // convert one dimensional polynomial with ext coeff to full dense representation
4368   // back conversion is convert_back (template coefficients)
convert(const vector<T_unsigned<vector<int>,hashgcd_U>> & p,hashgcd_U var,vector<vector<int>> & v)4369   static void convert(const vector< T_unsigned<vector<int>,hashgcd_U> > & p,hashgcd_U var,vector< vector<int> > & v){
4370     v.clear();
4371     vector< T_unsigned<vector<int>,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
4372     if (it==itend)
4373       return;
4374     hashgcd_U u=it->u;
4375     unsigned s=u/var;
4376     v=vector< vector<int> >(s+1);
4377     for (;it!=itend;++it){
4378       v[s-it->u/var]=it->g;
4379     }
4380   }
4381 
4382   // find n and d such that n/d=a mod m, modulo
4383   // and deg(n) <= deg(m)/2, deg(d) <= deg(m)-deg(a)
4384   // n=m*u+a*d,
4385   // Bezout for m and a, m*u_k + a*v_k = r_k, stop when deg(r_k)<=deg(m)/2
4386   // n=r_k and d=v_k, then check that d is prime with m and n
polyfracmod(const vector<int> & a,const vector<int> & m,int modulo,vector<int> & n,vector<int> & d)4387   static bool polyfracmod(const vector<int> & a,const vector<int> &m,int modulo,vector<int> & n, vector<int> & d){
4388     vector<int> r0(m),r1(a),r2,v0,v1(1,1),v2,q,tmp;
4389     // m*u0+a*v0=m=r0, m*u1+a*v1=a=r1, u0, u1 and u2 are not computed (not used)
4390     int N=int(m.size()-1)/2;
4391     for (;(int)r1.size()>N+1;){
4392       DivRem(r0,r1,modulo,q,r2);
4393       smallmult(q.begin(),q.end(),v1.begin(),v1.end(),tmp,modulo);
4394       swap(v0,v2); // v2=v0; but v0 is not used anymore
4395       submod(v2,tmp,modulo);
4396       // move r1 to r0 and r2 to r1, same with v
4397       // A B C
4398       swap(r0,r1); // B A C
4399       swap(r1,r2); // B C A
4400       // unused B C
4401       swap(v0,v1); // B unused C
4402       swap(v1,v2); // B C unused
4403     }
4404     // deg(r1)<=N, store answer
4405     swap(r1,n);
4406     swap(v1,d);
4407     // checks
4408     gcdsmallmodpoly(d,m,modulo,r2);
4409     if (r2.size()>1)
4410       return false;
4411     gcdsmallmodpoly(n,d,modulo,r2);
4412     if (r2.size()>1)
4413       return false;
4414     return true;
4415   }
4416 
polyfracmod(const gen & g,const vector<int> & m,int modulo,gen & res)4417   static bool polyfracmod(const gen & g,const vector<int> & m,int modulo,gen & res){
4418     if (g.type==_POLY){
4419       polynome p(g._POLYptr->dim);
4420       vector<monomial<gen> >::const_iterator it=g._POLYptr->coord.begin(),itend=g._POLYptr->coord.end();
4421       for (;it!=itend;++it){
4422 	const gen tmp=it->value;
4423 	gen x;
4424 	if (tmp.type!=_VECT)
4425 	  p.coord.push_back(monomial<gen>(tmp,it->index));
4426 	else {
4427 	  polyfracmod(*tmp._VECTptr,m,modulo,x);
4428 	  p.coord.push_back(monomial<gen>(x,it->index));
4429 	}
4430       }
4431       res=p;
4432       return true;
4433     }
4434     if (g.type!=_VECT){
4435       res=g;
4436       return true;
4437     }
4438     if (g._VECTptr->size()-1<=(m.size()-1)/2){
4439       res=g;
4440       return true;
4441     }
4442     // FIXME coeffs might be polynomials instead of integers
4443     vector<int> a,n,d;
4444     vecteur N,D;
4445     vecteur2vector_int(*g._VECTptr,modulo,a);
4446     if (!polyfracmod(a,m,modulo,n,d))
4447       return false;
4448     vector_int2vecteur(n,N);
4449     vector_int2vecteur(d,D);
4450     res=fraction(N,D);
4451     return true;
4452   }
4453 
polyfracmod(vecteur & res,const vector<int> & m,int modulo)4454   static bool polyfracmod(vecteur & res,const vector<int> & m,int modulo){
4455     iterateur it=res.begin(),itend=res.end();
4456     for (;it!=itend;++it){
4457       if (!polyfracmod(*it,m,modulo,*it))
4458 	return false;
4459     }
4460     return true;
4461   }
4462 
4463   // replace p by lcm of p and g
vlcm(modpoly & p,const gen & g,int modulo)4464   static bool vlcm(modpoly & p,const gen & g,int modulo){
4465     if (g.type!=_VECT)
4466       return true;
4467     const modpoly & q=*g._VECTptr;
4468     environment env;
4469     env.modulo=modulo;
4470     env.moduloon=true;
4471     modpoly quo,rem,pgcd;
4472     // first check if g divides p
4473     if (!DivRem(p,q,&env,quo,rem,false))
4474       return false; // setsizeerr();
4475     if (rem.empty())
4476       return true;
4477     // nope, compute gcd and divide p*q by gcd
4478     gcdmodpoly(p,q,&env,pgcd);
4479     if (is_undef(pgcd))
4480       return false;
4481     DivRem(p,pgcd,&env,quo,rem);
4482     mulmodpoly(q,quo,&env,p);
4483     return true;
4484   }
4485 
4486   // rational recon and clear fraction, return size of lcm of denom
polyfracmod(const vector<T_unsigned<vecteur,hashgcd_U>> & p0,const vector<int> & m,int modulo,vector<T_unsigned<vecteur,hashgcd_U>> & p,int maxdeg)4487   static int polyfracmod(const vector< T_unsigned<vecteur,hashgcd_U> > & p0,const vector<int> & m,int modulo,vector< T_unsigned<vecteur,hashgcd_U> > & p,int maxdeg){
4488     p=p0;
4489     vector< T_unsigned<vecteur,hashgcd_U> >::iterator kt=p.begin(),ktend=p.end();
4490     for (;kt!=ktend;++kt){
4491       if (!polyfracmod(kt->g,m,modulo))
4492 	return 0;
4493     }
4494     // find lcm of deno
4495     vecteur ppcm(1,1);
4496     for (kt=p.begin();kt!=ktend;++kt){
4497       if ((int)ppcm.size()>maxdeg+1)
4498 	return 0;
4499       iterateur it=kt->g.begin(),itend=kt->g.end();
4500       for (;it!=itend;++it){
4501 	if (it->type==_FRAC){
4502 	  if (!vlcm(ppcm,it->_FRACptr->den,modulo))
4503 	    return 0;
4504 	  if ((int)ppcm.size()>maxdeg+1)
4505 	    return 0;
4506 	}
4507 	else {
4508 	  if (it->type==_POLY){
4509 	    vector< monomial<gen> >::const_iterator jt=it->_POLYptr->coord.begin(),jtend=it->_POLYptr->coord.end();
4510 	    for (;jt!=jtend;++jt){
4511 	      if (jt->value.type==_FRAC){
4512 		if (!vlcm(ppcm,jt->value._FRACptr->den,modulo))
4513 		  return 0;
4514 		if ((int)ppcm.size()>maxdeg+1)
4515 		  return 0;
4516 	      }
4517 	    }
4518 	  }
4519 	}
4520       }
4521     }
4522     // clear deno
4523     gen den(ppcm,_POLY1__VECT);
4524     environment env;
4525     env.modulo=modulo;
4526     env.moduloon=true;
4527     if (ppcm.size()>1){
4528       gen adjust=invmod(ppcm.front(),modulo);
4529       if (is_undef(adjust))
4530 	return 0;
4531       for (kt=p.begin();kt!=ktend;++kt){
4532 	iterateur it=kt->g.begin(),itend=kt->g.end();
4533 	for (;it!=itend;++it){
4534 	  if (it->type==_FRAC){
4535 	    if (it->_FRACptr->den.type!=_VECT)
4536 	      return 0; // setsizeerr();
4537 	    modpoly quot,rest;
4538 	    if (!DivRem(ppcm,*it->_FRACptr->den._VECTptr,&env,quot,rest,false) || !rest.empty())
4539 	      return 0; // setsizeerr();
4540 	    *it = smod(adjust*(it->_FRACptr->num * gen(quot,_POLY1__VECT)),modulo);
4541 	  }
4542 	  else {
4543 	    if (it->type==_POLY){
4544 	      vector< monomial<gen> >::iterator jt=it->_POLYptr->coord.begin(),jtend=it->_POLYptr->coord.end();
4545 	      for (;jt!=jtend;++jt){
4546 		if (jt->value.type==_FRAC){
4547 		  modpoly quot,rest;
4548 		  if (!DivRem(ppcm,*jt->value._FRACptr->den._VECTptr,&env,quot,rest,false) || !rest.empty())
4549 		    return 0; // setsizeerr();
4550 		  jt->value = smod(adjust*(jt->value._FRACptr->num * gen(quot,_POLY1__VECT)),modulo);
4551 		}
4552 		else
4553 		  jt->value = smod(adjust*(den * jt->value),modulo) ;
4554 	      }
4555 	    }
4556 	    else
4557 	      *it = smod(adjust*den * (*it),modulo);
4558 	  }
4559 	}
4560       }
4561     }
4562     return int(ppcm.size());
4563   }
4564 
gentoint(const vector<T_unsigned<vecteur,hashgcd_U>> & p0,vector<T_unsigned<vector<int>,hashgcd_U>> & p)4565   static bool gentoint(const vector< T_unsigned<vecteur,hashgcd_U> > & p0,vector< T_unsigned<vector<int>,hashgcd_U> > & p){
4566     vector< T_unsigned<vecteur,hashgcd_U> >::const_iterator it=p0.begin(),itend=p0.end();
4567     p.clear();
4568     p.reserve(itend-it);
4569     for (;it!=itend;++it){
4570       vecteur::const_iterator jt=it->g.begin(),jtend=it->g.end();
4571       p.push_back(T_unsigned<vector<int>,hashgcd_U>(vector<int>(0),it->u));
4572       vector<int> & res=p.back().g;
4573       for (;jt!=jtend;++jt){
4574 	if (jt->type!=_INT_)
4575 	  return false;
4576 	res.push_back(jt->val);
4577       }
4578     }
4579     return true;
4580   }
4581 
inttogen(const vector<T_unsigned<vector<int>,hashgcd_U>> & p0,vector<T_unsigned<vecteur,hashgcd_U>> & p)4582   static void inttogen(const vector< T_unsigned<vector<int>,hashgcd_U> > & p0,vector< T_unsigned<vecteur,hashgcd_U> > & p){
4583     vector< T_unsigned<vector<int>,hashgcd_U> >::const_iterator it=p0.begin(),itend=p0.end();
4584     p.clear();
4585     p.reserve(itend-it);
4586     for (;it!=itend;++it){
4587       vector<int>::const_iterator jt=it->g.begin(),jtend=it->g.end();
4588       p.push_back(T_unsigned<vecteur,hashgcd_U>(vecteur(0),it->u));
4589       vecteur & res=p.back().g;
4590       for (;jt!=jtend;++jt){
4591 	res.push_back(*jt);
4592       }
4593     }
4594   }
4595 
4596   // eval last variable of polynomials in g at x modulo modulo, answer in res
4597   // polynomial coeff must be integers
horner_back_ext(const gen & g,int x,int modulo,gen & res)4598   static bool horner_back_ext(const gen & g,int x,int modulo,gen & res){
4599     if (g.type!=_POLY){
4600       if (g.type==_FRAC){
4601 	gen r1,r2;
4602 	if (!horner_back_ext(g._FRACptr->num,x,modulo,r1) ||
4603 	    !horner_back_ext(g._FRACptr->den,x,modulo,r2))
4604 	  return false;
4605 	res=r1/r2;
4606 	return true;
4607       }
4608       if (g.type==_EXT){
4609 	gen r1,r2;
4610 	if (!horner_back_ext(*g._EXTptr,x,modulo,r1) ||
4611 	    !horner_back_ext(*(g._EXTptr+1),x,modulo,r2))
4612 	  return false;
4613 	res=algebraic_EXTension(r1,r2);
4614 	return true;
4615       }
4616       if (g.type!=_VECT){
4617 	res=g;
4618 	return true;
4619       }
4620       res=gen(*g._VECTptr,g.subtype);
4621       if (res.type!=_VECT)
4622 	return true;
4623       gen tmp;
4624       iterateur it=res._VECTptr->begin(),itend=res._VECTptr->end();
4625       for (;it!=itend;++it){
4626 	if (!horner_back_ext(*it,x,modulo,tmp))
4627 	  return false;
4628 	*it=tmp;
4629       }
4630       return true;
4631     }
4632     const polynome & p = *g._POLYptr;
4633     int dim=p.dim;
4634     polynome r(dim-1);
4635     vector< monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
4636     if (it==itend){
4637       res=0;
4638       return true;
4639     }
4640     index_t current(it->index.begin(),it->index.begin()+dim-1),nouveau(dim-1);
4641     int expo=it->index.back(),newexpo;
4642     if (it->value.type!=_INT_)
4643       return false; // setsizeerr();
4644     int val=it->value.val;
4645     for (++it;it!=itend;++it){
4646       // IMPROVE: for dense poly: skip to it+expo check if same outer exponents
4647       if (it->value.type!=_INT_)
4648 	return false; // setsizeerr();
4649       index_t::iterator nit=nouveau.begin();
4650       index_t::const_iterator jt=it->index.begin(),jtend=it->index.begin()+dim-1;
4651       for (;jt!=jtend;++nit,++jt){
4652 	*nit=*jt;
4653       }
4654       if (nouveau==current){
4655 	val=(powmod(x,expo-(newexpo=it->index.back()),modulo)*longlong(val)+it->value.val)%modulo;
4656 	expo=newexpo;
4657 	continue;
4658       }
4659       if (expo)
4660 	val=(powmod(x,expo,modulo)*longlong(val))%modulo;
4661       r.coord.push_back(monomial<gen>(val,current));
4662       swap(current,nouveau);
4663       val=it->value.val;
4664       expo=it->index.back();
4665     }
4666     if (expo)
4667       val=(powmod(x,expo,modulo)*longlong(val))%modulo;
4668     r.coord.push_back(monomial<gen>(val,current));
4669     res=r;
4670     return true;
4671   }
4672 
4673   // return false if the lcoeff is 0
horner_back_ext2(const vector<T_unsigned<vecteur,hashgcd_U>> & g,int x,int modulo,vector<T_unsigned<vecteur,hashgcd_U>> & res)4674   static bool horner_back_ext2(const vector< T_unsigned<vecteur,hashgcd_U> > & g,int x,int modulo,vector< T_unsigned<vecteur,hashgcd_U> > & res){
4675     gen tmp;
4676     res.clear();
4677     vector< T_unsigned<vecteur,hashgcd_U> >::const_iterator it=g.begin(),itend=g.end();
4678     bool b=true;
4679     for (;it!=itend;++it){
4680       if (!horner_back_ext(it->g,x,modulo,tmp))
4681 	return false;
4682       if (is_zero(tmp)){
4683 	if (it==res.begin())
4684 	  b=false;
4685 	continue;
4686       }
4687       if (tmp.type==_VECT)
4688 	res.push_back(T_unsigned<vecteur,hashgcd_U>(*tmp._VECTptr,it->u));
4689       else
4690 	res.push_back(T_unsigned<vecteur,hashgcd_U>(vecteur(1,tmp),it->u));
4691     }
4692     return b;
4693   }
4694 
4695   struct ext_gcd_t {
4696     gen pi_t_minus_tk;
4697     vector< T_unsigned<vecteur,hashgcd_U> > lagrange;
4698     // the vecteur represents dependency wrt the extension variable (z)
4699     // each coeff depends on t1..tk-1 variable as a _POLY
4700     // the depency wrt tk is represented by coeffs=vecteur of type poly1[]
4701   };
4702 
hornermod(const gen & g,int tk,int modulo)4703   static gen hornermod(const gen & g,int tk,int modulo){
4704     if (g.type==_POLY){
4705       polynome res(g._POLYptr->dim);
4706       vector< monomial<gen> >::const_iterator it=g._POLYptr->coord.begin(),itend=g._POLYptr->coord.end();
4707       for (;it!=itend;++it){
4708 	gen tmp=hornermod(it->value,tk,modulo);
4709 	if (!is_zero(tmp))
4710 	  res.coord.push_back(monomial<gen>(tmp,it->index));
4711       }
4712       return res;
4713     }
4714     if (g.type!=_VECT)
4715       return g;
4716     int res=0;
4717     const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
4718     for (;it!=itend;++it){
4719       res = ( res*longlong(tk)+it->val)%modulo;
4720     }
4721     return res;
4722   }
4723 
interp_tk(const vecteur & interp_ancien,const gen & ancienpi,const vecteur & interp_tk,int tk,int modulo)4724   static vecteur interp_tk(const vecteur & interp_ancien,const gen & ancienpi,const vecteur & interp_tk,int tk,int modulo){
4725     int as=int(interp_ancien.size()),bs=int(interp_tk.size()),cs=giacmax(as,bs);
4726     vecteur res(cs);
4727     gen pi(hornermod(ancienpi,tk,modulo));
4728     if (pi.type!=_INT_)
4729       return vecteur(1,gensizeerr(gettext("interp_tk")));
4730     int invpi=invmod(pi.val,modulo);
4731     for (int i=0;i<cs;++i){
4732       gen old=0,nouv=0;
4733       if (i+as>=cs) old=hornermod(interp_ancien[i+as-cs],tk,modulo);
4734       if (i+bs>=cs) nouv=interp_tk[i+bs-cs];
4735       gen alpha=smod(invpi*(nouv-old),modulo);
4736       // multiply by ancienpi and add to interp_ancien
4737       if (alpha.type==_POLY)
4738 	alpha=ancienpi * (*alpha._POLYptr);
4739       else
4740 	alpha=ancienpi*alpha;
4741       if (i+as>=cs){
4742 	gen g =interp_ancien[i+as-cs];
4743 	if (g.type==_POLY && alpha.type!=_POLY)
4744 	  res[i]=smod(addpoly(*g._POLYptr,alpha),modulo);
4745 	else {
4746 	  if (g.type!=_POLY && alpha.type==_POLY)
4747 	    res[i]=smod(addpoly(*alpha._POLYptr,g),modulo);
4748 	  else
4749 	    res[i]=smod(g+alpha,modulo);
4750 	}
4751       }
4752       else
4753 	res[i]=smod(alpha,modulo);
4754     }
4755     return res;
4756   }
4757 
untrunc(gen & g,int innerdim)4758   static void untrunc(gen & g,int innerdim){
4759     if (g.type==_VECT){
4760       polynome p(innerdim);
4761       index_t i(innerdim);
4762       const_iterateur jt=g._VECTptr->begin(),jtend=g._VECTptr->end();
4763       if (jtend==jt){
4764 	g=0;
4765 	return;
4766       }
4767       i.back()=int(jtend-jt)-1;
4768       for (;jt!=jtend;--i.back(),++jt){
4769 	if (!is_zero(*jt))
4770 	  p.coord.push_back(monomial<gen>(*jt,i));
4771       }
4772       g=p;
4773       return;
4774     }
4775     if (g.type!=_POLY)
4776       return;
4777     polynome p(innerdim);
4778     vector< monomial<gen> >::const_iterator it=g._POLYptr->coord.begin(),itend=g._POLYptr->coord.end();
4779     for (;it!=itend;++it){
4780       index_t i(it->index.iref());
4781       i.push_back(0);
4782       if (it->value.type!=_VECT)
4783 	p.coord.push_back(monomial<gen>(it->value,i));
4784       else {
4785 	const_iterateur jt=it->value._VECTptr->begin(),jtend=it->value._VECTptr->end();
4786 	if (jtend==jt)
4787 	  continue;
4788 	i.back()=int(jtend-jt)-1;
4789 	for (;jt!=jtend;--i.back(),++jt){
4790 	  if (!is_zero(*jt))
4791 	    p.coord.push_back(monomial<gen>(*jt,i));
4792 	}
4793       }
4794     }
4795     g=p;
4796   }
4797 
untrunc(vector<T_unsigned<vecteur,hashgcd_U>> & p,int dim)4798   static void untrunc(vector< T_unsigned<vecteur,hashgcd_U> > & p,int dim){
4799     vector< T_unsigned<vecteur,hashgcd_U> >::iterator it=p.begin(),itend=p.end();
4800     for (;it!=itend;++it){
4801       iterateur jt=it->g.begin(),jtend=it->g.end();
4802       for (;jt!=jtend;++jt)
4803 	untrunc(*jt,dim);
4804     }
4805   }
4806 
gcd_ext(const vector<T_unsigned<vecteur,hashgcd_U>> & p0,const vector<T_unsigned<vecteur,hashgcd_U>> & q0,const std::vector<hashgcd_U> & vars,const vecteur & Pmin,int modulo,vector<T_unsigned<vecteur,hashgcd_U>> & D,vector<T_unsigned<vecteur,hashgcd_U>> & Pcof,vector<T_unsigned<vecteur,hashgcd_U>> & Qcof,bool compute_pcof,bool compute_qcof,int nthreads)4807   static int gcd_ext(const vector< T_unsigned<vecteur,hashgcd_U> > & p0,const vector< T_unsigned<vecteur,hashgcd_U> > & q0,const std::vector<hashgcd_U> & vars,const vecteur & Pmin,int modulo,
4808 	       vector< T_unsigned<vecteur,hashgcd_U> > & D,
4809 	       vector< T_unsigned<vecteur,hashgcd_U> > & Pcof,vector< T_unsigned<vecteur,hashgcd_U> > & Qcof,bool compute_pcof,bool compute_qcof,
4810 	       int nthreads){
4811 #ifdef NO_TEMPLATE_MULTGCD
4812     return 0;
4813 #else
4814     // FIXME cofactors are not yet implemented
4815     gen extension;
4816     const_iterateur it=Pmin.begin(),itend=Pmin.end();
4817     for (;it!=itend;++it){
4818       if (it->type==_POLY)
4819 	extension=*it;
4820       else {
4821 	if (!it->is_integer())
4822 	  return 0;
4823       }
4824     }
4825     if (extension.type==_POLY){
4826       // return -1; // avoid inf loop while not implemented
4827       Modred pminmodulo(modulo,Pmin);
4828       // otherwise give ext variables values, subroutine P van Hoeij-Monagan
4829       // Algo. for Polynomial GCD computation over Algebraic Function Fields
4830       int d=1,n=1,innerdim=extension._POLYptr->dim;
4831       if (innerdim<1)
4832 	return 0; // setsizeerr();
4833       map<pair<hashgcd_U,index_t>,ext_gcd_t> m;
4834       // index is obtained by taking lcoeff with respect to outer var
4835       // (hashgcd_U) and inner var (index_t)
4836       vector< T_unsigned<vecteur,hashgcd_U> > p0tk,q0tk,dtk,pcoftk,qcoftk,nouveau,test,prevtest,tmprem;
4837       for (int tcount=0;;++tcount){
4838 	int tk=giac_rand(context0) % modulo;
4839 	gen pmintk;
4840 	if (!horner_back_ext(Pmin,tk,modulo,pmintk))
4841 	  return 0;
4842 	if (pmintk.type!=_VECT)
4843 	  continue;
4844 	vecteur & Pmintk = *pmintk._VECTptr;
4845 	if (is_zero(Pmintk.front()))
4846 	  continue;
4847 	if (!horner_back_ext2(p0,tk,modulo,p0tk))
4848 	  continue;
4849 	if (!horner_back_ext2(q0,tk,modulo,q0tk))
4850 	  continue;
4851 	int res=gcd_ext(p0tk,q0tk,vars,Pmintk,modulo,dtk,pcoftk,qcoftk,false,false,nthreads);
4852 	if (res==-1)
4853 	  return -1;
4854 	if (res!=1){
4855 	  ++d;
4856 	  if (d>n)
4857 	    return 0;
4858 	  else
4859 	    continue;
4860 	}
4861 	// dtk lcoeff should not depend on extension variable
4862 	if (dtk.empty())
4863 	  return 0; // setsizeerr();
4864 	vecteur & lcoeffdtk = dtk.front().g;
4865 	if (lcoeffdtk.size()!=1)
4866 	  return 0; // setsizeerr();
4867 	index_t innerlcoeff(innerdim-1);
4868 	if (lcoeffdtk.front().type==_POLY && !lcoeffdtk.front()._POLYptr->coord.empty())
4869 	  innerlcoeff=lcoeffdtk.front()._POLYptr->coord.front().index.iref();
4870 	// adjust m[pair(dtk.front().u,innerlcoeff)]
4871 	pair<hashgcd_U,index_t> pa(dtk.front().u,innerlcoeff);
4872 	map<pair<hashgcd_U,index_t>,ext_gcd_t>::iterator jt=m.find(pa),jtend=m.end();
4873 	if (jt==jtend){
4874 	  m[pa].pi_t_minus_tk=gen(makevecteur(1,-tk),_POLY1__VECT);
4875 	  m[pa].lagrange=dtk;
4876 	}
4877 	else {
4878 	  gen ancienpi=m[pa].pi_t_minus_tk;
4879 	  vector< T_unsigned<vecteur,hashgcd_U> >::iterator jt=m[pa].lagrange.begin(),jtend=m[pa].lagrange.end(),kt=dtk.begin(),ktend=dtk.end();
4880 	  nouveau.clear();
4881 	  for (;;){
4882 	    if (jt==jtend && kt==ktend)
4883 	      break;
4884 	    if (jt==jtend || jt->u>kt->u){
4885 	      nouveau.push_back(T_unsigned<vecteur,hashgcd_U>(interp_tk(vecteur(0),ancienpi,kt->g,tk,modulo),kt->u));
4886 	      ++kt;
4887 	      continue;
4888 	    }
4889 	    if (kt==ktend || jt->u<kt->u){
4890 	      nouveau.push_back(T_unsigned<vecteur,hashgcd_U>(interp_tk(jt->g,ancienpi,vecteur(0),tk,modulo),jt->u));
4891 	      ++jt;
4892 	      continue;
4893 	    }
4894 	    nouveau.push_back(T_unsigned<vecteur,hashgcd_U>(interp_tk(jt->g,ancienpi,kt->g,tk,modulo),kt->u));
4895 	    ++jt;
4896 	    ++kt;
4897 	  }
4898 	  swap(m[pa].lagrange,nouveau);
4899 	  m[pa].pi_t_minus_tk=smod(ancienpi*gen(makevecteur(1,-tk),_POLY1__VECT),modulo);
4900 	}
4901 	// rational reconstruction for m[pa].lagrange modulo m[pa].pi_tk_minus_t
4902 	// must be done on each component of the vecteur
4903 	// which should be either a poly1[] or a _POLY with poly1[] coeffs
4904 	// Clear fractions dependency wrt tk variable
4905 	vector<int> mo;
4906 	vecteur2vector_int(*m[pa].pi_t_minus_tk._VECTptr,modulo,mo);
4907 	if (!polyfracmod(m[pa].lagrange,mo,modulo,test,tcount))
4908 	  continue;
4909 	// now replace inner tk dependency as a poly1[] to an usual polynome
4910 	untrunc(test,innerdim);
4911 	// ?CHECK? clean lcoeff so that it is 1 wrt extension variable z
4912 	// trial division, if success return 1 else continue
4913 	// ?FIXME? use pseudo-division test
4914 	if (debug_infolevel)
4915 	  CERR << CLOCK() << " algmodgcd hashdivrem " << test.size() <<'\n';// << " " << test << '\n';
4916 	if (test==prevtest && hashdivrem(p0,test,Pcof,tmprem,vars,pminmodulo,0,true)==1 && tmprem.empty()){
4917 	  if (hashdivrem(q0,test,Qcof,tmprem,vars,pminmodulo,0,true)==1 && tmprem.empty()){
4918 	    if (debug_infolevel)
4919 	      CERR << CLOCK() << " algmodgcd hashdivrem sucess" << '\n';
4920 	    D=test;
4921 	    return 1;
4922 	  }
4923 	}
4924 	prevtest=test;
4925 	if (debug_infolevel)
4926 	  CERR << CLOCK() << " algmodgcd hashdivrem failure" << '\n';
4927       }
4928     } // end extension.type==_POLY
4929     // int dim=vars.size();
4930     vector< T_unsigned<vector<int>,hashgcd_U> > p_orig,q_orig,d,pcof,qcof;
4931     if (!gentoint(p0,p_orig) || !gentoint(q0,q_orig))
4932       return 0;
4933     // ok, ext of dim 0
4934     vector<int> pmin;
4935     vecteur2vector_int(Pmin,modulo,pmin);
4936     int res=mod_gcd_ext(p_orig,q_orig,vars,pmin,modulo,d,pcof,qcof,compute_pcof,compute_qcof,nthreads);
4937     // convert back
4938     inttogen(d,D);
4939     if (compute_pcof)
4940       inttogen(pcof,Pcof);
4941     if (compute_qcof)
4942       inttogen(qcof,Qcof);
4943     return res;
4944 #endif // NO_TEMPLATE_MULTGCD
4945   }
4946 
operator /(const vector<int> & v,const vector<int> & b)4947   vector<int> operator / (const vector<int> & v,const vector<int> & b){
4948 #ifndef NO_STDEXCEPT
4949     setsizeerr(gettext("vector<int> operator /"));
4950 #endif
4951     return v;
4952   }
4953 
operator %(const vector<int> & v,const vector<int> & b)4954   vector<int> operator % (const vector<int> & v,const vector<int> & b){
4955 #ifndef NO_STDEXCEPT
4956     setsizeerr(gettext("vector<int> operator %"));
4957 #endif
4958     return v;
4959   }
4960 
operator >(const vector<int> & v,double q)4961   bool operator > (const vector<int> & v,double q){
4962 #ifndef NO_STDEXCEPT
4963     setsizeerr(gettext("vector<int> operator >"));
4964 #endif
4965     return false;
4966   }
4967 
trim(const std::vector<int> & res)4968   static std::vector<int> trim(const std::vector<int> & res){
4969     // trim res
4970     std::vector<int>::const_iterator ita=res.begin(),itaend=res.end();
4971     for (;ita!=itaend;++ita){
4972       if (*ita)
4973 	break;
4974     }
4975     return vector<int>(ita,itaend);
4976   }
4977 
operator +(const std::vector<int> & a,const std::vector<int> & b)4978   std::vector<int> operator + (const std::vector<int> & a, const std::vector<int> & b){
4979     std::vector<int>::const_iterator ita=a.begin(),itaend=a.end(),itb=b.begin(),itbend=b.end();
4980     unsigned s=unsigned(itaend-ita),t=unsigned(itbend-itb);
4981     if (s>=t){
4982       std::vector<int> res(a);
4983       std::vector<int>::iterator itres=res.begin()+(s-t);
4984       for (;itb!=itbend;++itb,++itres)
4985 	*itres += (*itb);
4986       if (res.empty() || res.front())
4987 	return res;
4988       return trim(res);
4989     }
4990     std::vector<int> res(b);
4991     std::vector<int>::iterator itres=res.begin()+(t-s);
4992     for (;ita!=itaend;++ita,++itres)
4993       *itres += (*ita);
4994     return res;
4995   }
4996 
operator -(const std::vector<int> & a,const std::vector<int> & b)4997   std::vector<int> operator - (const std::vector<int> & a, const std::vector<int> & b){
4998     std::vector<int>::const_iterator ita=a.begin(),itaend=a.end(),itb=b.begin(),itbend=b.end();
4999     unsigned s=unsigned(itaend-ita),t=unsigned(itbend-itb);
5000     if (s>=t){
5001       std::vector<int> res(a);
5002       std::vector<int>::iterator itres=res.begin()+(s-t);
5003       for (;itb!=itbend;++itb,++itres)
5004 	*itres -= (*itb);
5005       if (res.empty() || res.front())
5006 	return res;
5007       // trim res
5008       return trim(res);
5009     }
5010     std::vector<int> res(b);
5011     std::vector<int>::iterator itres=res.begin();
5012     for (;t>s;--t,++itres)
5013       *itres = -*itres;
5014     for (;ita!=itaend;++ita,++itres)
5015       *itres = *ita - *itres;
5016     return res;
5017   }
5018 
operator -(const std::vector<int> & a)5019   std::vector<int> operator - (const std::vector<int> & a){
5020     std::vector<int> res(a);
5021     std::vector<int>::iterator ita=res.begin(),itaend=res.end();
5022     for (;ita!=itaend;++ita)
5023       *ita = -*ita;
5024     return res;
5025   }
5026 
operator %(const std::vector<int> & a,int modulo)5027   std::vector<int> operator % (const std::vector<int> & a,int modulo){
5028     std::vector<int> res(a);
5029     std::vector<int>::iterator ita=res.begin(),itaend=res.end();
5030     for (;ita!=itaend;++ita)
5031       *ita %= modulo;
5032     if (res.empty() || res.front())
5033       return res;
5034     // trim res
5035     return trim(res);
5036   }
5037 
distmult_ext(const vector<T_unsigned<vector<int>,hashgcd_U>> & p,const vector<vector<int>> & v,vector<T_unsigned<vector<int>,hashgcd_U>> & pv,hashgcd_U var,const vector<int> & pmin,int modulo)5038   static void distmult_ext(const vector< T_unsigned<vector<int>,hashgcd_U> > & p,const vector< vector<int> > & v,vector< T_unsigned<vector<int>,hashgcd_U> > & pv,hashgcd_U var,const vector<int> & pmin,int modulo){
5039     if (&pv==&p){
5040       vector< T_unsigned<vector<int>,hashgcd_U> > tmp;
5041       distmult_ext(p,v,tmp,var,pmin,modulo);
5042       swap(pv,tmp);
5043       return;
5044     }
5045     pv.clear();
5046     vector< T_unsigned<vector<int>,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
5047     vector< vector<int> >::const_iterator jtbeg=v.begin(),jtend=v.end(),jt;
5048     int vs=int(jtend-jtbeg),j;
5049     pv.reserve((itend-it)*vs);
5050     for (;it!=itend;++it){
5051       for (jt=jtbeg,j=1;jt!=jtend;++j,++jt){
5052 	if (!is_zero(*jt)){
5053 	  vector<int> tmp;
5054 	  mulext(it->g,*jt,pmin,modulo,tmp);
5055 	  pv.push_back( T_unsigned< vector<int>,hashgcd_U >(tmp,it->u+(vs-j)*var));
5056         }
5057       }
5058     }
5059   }
5060 
horner(const vector<T_unsigned<vector<int>,hashgcd_U>> & p,int x,const std::vector<hashgcd_U> & vars,vector<T_unsigned<vector<int>,hashgcd_U>> & px,int modulo,int maxdeg)5061   static bool horner(const vector< T_unsigned<vector<int>,hashgcd_U> > & p,int x,const std::vector<hashgcd_U> & vars,vector< T_unsigned<vector<int>,hashgcd_U> > & px,int modulo,int maxdeg){
5062     px.clear();
5063     hashgcd_U var=vars[vars.size()-2];
5064     hashgcd_U var2=vars.back();
5065     vector< T_unsigned<vector<int>,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end(),it1;
5066     vector<hashgcd_U>::const_iterator jtend=vars.end()-1;
5067     hashgcd_U ucur,uend;
5068     if (maxdeg>=0){
5069       uend=(maxdeg+1)*vars.front();
5070       // dichotomy to find start position
5071       int pos1=0,pos2=int(itend-it),pos;
5072       for (;pos2-pos1>1;){
5073 	pos=(pos1+pos2)/2;
5074 	if ((it+pos)->u<uend)
5075 	  pos2=pos;
5076 	else
5077 	  pos1=pos;
5078       }
5079       it += pos1;
5080       if (it->u>=uend)
5081 	++it;
5082     }
5083     if (x==0){
5084       for (;it!=itend;){
5085 	ucur=it->u;
5086 	uend=(ucur/var)*var;
5087 	if (ucur==uend){
5088 	  const vector<int> & g=smod(it->g,modulo);
5089 	  if (!is_zero(g))
5090 	    px.push_back(T_unsigned<vector<int>,hashgcd_U>(g,uend));
5091 	  ++it;
5092 	  continue;
5093 	}
5094 	register int nterms = (ucur-uend)/var2;
5095 	if (nterms<itend-it && (it+nterms)->u==uend){
5096 	  it += nterms;
5097 	  const vector<int> & g=smod(it->g,modulo);
5098 	  if (!is_zero(g))
5099 	    px.push_back(T_unsigned<vector<int>,hashgcd_U>(g,uend));
5100 	  ++it;
5101 	  continue;
5102 	}
5103 	for (++it;it!=itend;++it){
5104 	  if (it->u<=uend){
5105 	    if (it->u==uend){
5106 	      const vector<int> & g=smod(it->g,modulo);
5107 	      if (!is_zero(g))
5108 		px.push_back(T_unsigned<vector<int>,hashgcd_U>(g,uend));
5109 	      ++it;
5110 	    }
5111 	    break;
5112 	  }
5113 	}
5114       }
5115       return true;
5116     }
5117     for (;it!=itend;){
5118       ucur=it->u;
5119       uend=(ucur/var)*var;
5120       if (ucur==uend){
5121 	px.push_back(*it);
5122 	++it;
5123 	continue;
5124       }
5125       vector<int> g(0);
5126       int nterms=(ucur-uend)/var2+1;
5127       // Check if the next group of monomials is dense wrt to xn
5128       it1=it+nterms;
5129       if (//false &&
5130 	  nterms<itend-it && (it1-1)->u==uend
5131 	  ){
5132 	for (;it!=it1;++it){
5133 	  // g = (g*x+it->g)%modulo;
5134 	  mulmod(g,x,modulo);
5135 	  addmod(g,it->g,modulo);
5136 	}
5137 	g=smod(g,modulo);
5138 	if (!is_zero(g))
5139 	  px.push_back(T_unsigned<vector<int>,hashgcd_U>(g,uend));
5140 	continue;
5141       }
5142       for (;it!=itend;++it){
5143 	const hashgcd_U & u=it->u;
5144 	if (u<uend){
5145 	  if (!is_zero(g)){
5146 	    mulmod(g,powmod(x,(ucur-uend)/var2,modulo),modulo);
5147 	    g = smod(g,modulo);
5148 	    if (!is_zero(g))
5149 	      px.push_back(T_unsigned<vector<int>,hashgcd_U>(g,uend));
5150 	  }
5151 	  break;
5152 	}
5153 	mulmod(g,powmod(x,(ucur-u)/var2,modulo),modulo);
5154 	addmod(g,it->g,modulo);
5155 	ucur=u;
5156       } // end for
5157       if (it==itend){
5158 	if (!is_zero(g)){
5159 	  mulmod(g,powmod(x,(ucur-uend)/var2,modulo),modulo);
5160 	  g=smod(g,modulo);
5161 	  if (!is_zero(g))
5162 	    px.push_back(T_unsigned<vector<int>,hashgcd_U>(g,uend));
5163 	}
5164       }
5165     }
5166     return true;
5167   }
5168 
5169 #ifndef NO_TEMPLATE_MULTGCD
do_recursive_gcd_ext_call(void * ptr_)5170   static void * do_recursive_gcd_ext_call(void * ptr_){
5171 #ifdef TIMEOUT
5172     control_c();
5173 #endif
5174     if (ctrl_c || interrupted)
5175       return 0;
5176     gcd_call_param< vector<int> > * ptr = (gcd_call_param< vector<int> > *) ptr_;
5177     vector< vector<int> > & Delta = *ptr->Delta;
5178     vector< vector<int> > & lcoeffp = *ptr->lcoeffp;
5179     vector< vector<int> > & lcoeffq = *ptr->lcoeffq;
5180     vector<int> & alphav = * ptr->alphav;
5181     // vector< vector< vector<int> > > & pv = *ptr->pv;
5182     // vector< vector< vector<int> > > & qv = *ptr->qv;
5183     vector< vector<int> > dim2palpha;
5184     vector< vector<int> > dim2qalpha;
5185     // vector< vector< vector<int> > > & dim2gcdv = *ptr->dim2gcdv;
5186     // vector< vector< vector<int> > > & dim2pcofactorv = *ptr->dim2pcofactorv;
5187     // vector< vector< vector<int> > > & dim2qcofactorv = *ptr->dim2qcofactorv;
5188     const vector< T_unsigned< vector<int> ,hashgcd_U> > & p = * ptr->p;
5189     const vector< T_unsigned< vector<int> ,hashgcd_U> > & q = * ptr->q;
5190     vector< vector< T_unsigned< vector<int> ,hashgcd_U> > > & gcdv = * ptr->gcdv;
5191     vector< vector< T_unsigned< vector<int> ,hashgcd_U> > > & pcofactorv = * ptr->pcofactorv;
5192     vector< vector< T_unsigned< vector<int> ,hashgcd_U> > > & qcofactorv = * ptr->qcofactorv;
5193     index_t & pdeg = * ptr->pdeg;
5194     index_t & qdeg = * ptr->qdeg;
5195     vector< T_unsigned< vector<int> ,hashgcd_U> > palpha,qalpha;
5196     index_t pdegalpha,qdegalpha;
5197     int vpos=ptr->vpos;
5198     int alpha1 = alphav[vpos];
5199     int modulo = ptr->modulo;
5200     const vector<int> & pmin = *ptr->pminptr;
5201     const vector<hashgcd_U> & vars = * ptr->vars;
5202     vector<hashgcd_U> & vars_truncated = * ptr->vars_truncated;
5203     // index_t & shift_vars = *ptr->shift_vars;
5204     index_t & shift_vars_truncated = *ptr->shift_vars_truncated;
5205     bool compute_cof = ptr->compute_cof;
5206     bool compute_qcofactor = ptr->compute_qcofactor;
5207     // bool dim2 = ptr->dim2;
5208     int nthreads = ptr->nthreads;
5209     // Eval p and q at xn=alpha
5210     if (!horner(p,alpha1,vars,palpha,modulo,-1))
5211       return 0;
5212     degree(palpha,shift_vars_truncated,pdegalpha);
5213     pdegalpha.push_back(pdeg.back());
5214     if (pdegalpha!=pdeg)
5215       return 0;
5216     if (!horner(q,alpha1,vars,qalpha,modulo,-1))
5217       return 0;
5218     degree(qalpha,shift_vars_truncated,qdegalpha);
5219     qdegalpha.push_back(qdeg.back());
5220     if (qdegalpha!=qdeg)
5221       return 0;
5222     vector< T_unsigned< vector<int> ,hashgcd_U> > & g=gcdv[vpos];
5223     vector< T_unsigned< vector<int> ,hashgcd_U> > & gp=pcofactorv[vpos];
5224     vector< T_unsigned< vector<int> ,hashgcd_U> > & gq=qcofactorv[vpos];
5225     if ( (ptr->ext_gcd_ok=mod_gcd_ext(palpha,qalpha,vars_truncated,pmin,modulo,g,gp,gq,compute_cof,compute_qcofactor,nthreads))!=1){
5226       g.clear();
5227       return ptr;
5228     }
5229     vector<int> tmp;
5230     // adjust lcoeff of gcd to be the same as Delta
5231     // smallmult(smod(hornermod(Delta,alpha1,modulo)*longlong(invmod(g.front().g,modulo)),modulo),g,g,modulo);
5232     if (!invmodext(g.front().g,pmin,modulo,tmp)){
5233       ptr->ext_gcd_ok=-1;
5234       return ptr;
5235     }
5236     mulext(tmp,hornermod_ext(Delta,alpha1,modulo),pmin,modulo);
5237     smallmult(tmp,g,g,modred(modulo,pmin));
5238     if (compute_cof){
5239       // adjust gp lcoeff
5240       // smallmult(smod(hornermod(lcoeffp,alpha1,modulo)*longlong(invmod(gp.front().g,modulo)),modulo),gp,gp,modulo);
5241       if (!invmodext(gp.front().g,pmin,modulo,tmp)){
5242 	ptr->ext_gcd_ok=-1;
5243 	return ptr;
5244       }
5245       mulext(tmp,hornermod_ext(lcoeffp,alpha1,modulo),pmin,modulo);
5246       smallmult(tmp,gp,gp,modred(modulo,pmin));
5247       if (compute_qcofactor){
5248 	// adjust gq cofactor
5249 	// smallmult(smod(hornermod(lcoeffq,alpha1,modulo)*longlong(invmod(gq.front().g,modulo)),modulo),gq,gq,modulo);
5250 	if (!invmodext(gq.front().g,pmin,modulo,tmp)){
5251 	  ptr->ext_gcd_ok=-1;
5252 	  return ptr;
5253 	}
5254 	mulext(tmp,hornermod_ext(lcoeffq,alpha1,modulo),pmin,modulo);
5255 	smallmult(tmp,gq,gq,modred(modulo,pmin));
5256       }
5257     }
5258     return ptr;
5259   }
5260 #endif //NO_TEMPLATE_MULTGCD
5261 
mod_gcd_ext(const vector<T_unsigned<vector<int>,hashgcd_U>> & p_orig,const vector<T_unsigned<vector<int>,hashgcd_U>> & q_orig,const std::vector<hashgcd_U> & vars,const vector<int> & pmin,int modulo,vector<T_unsigned<vector<int>,hashgcd_U>> & d,vector<T_unsigned<vector<int>,hashgcd_U>> & pcof,vector<T_unsigned<vector<int>,hashgcd_U>> & qcof,bool compute_pcofactor,bool compute_qcofactor,int nthreads)5262   static int mod_gcd_ext(const vector< T_unsigned<vector<int>,hashgcd_U> > & p_orig,const vector< T_unsigned<vector<int>,hashgcd_U> > & q_orig,const std::vector<hashgcd_U> & vars,const vector<int> & pmin,int modulo,
5263 	      vector< T_unsigned<vector<int>,hashgcd_U> > & d,
5264 	      vector< T_unsigned<vector<int>,hashgcd_U> > & pcof,vector< T_unsigned<vector<int>,hashgcd_U> > & qcof,bool compute_pcofactor,bool compute_qcofactor,
5265 	      int nthreads){
5266 #ifdef NO_TEMPLATE_MULTGCD
5267     return 0;
5268 #else
5269     //nthreads=1; // FIXME, !=1 segfaults on compaq mini
5270     hashgcd_U var=vars.front();
5271     int dim=int(vars.size());
5272     if (dim==1){
5273       vector< vector<int> > P,Q,D,cof,tmp;
5274       vector<int> tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7,tmp8;
5275       convert(p_orig,var,P);
5276       convert(q_orig,var,Q);
5277       if (!gcdsmallmodpoly_ext(P,Q,pmin,modulo,D))
5278 	return 0;
5279       // should compute pcof and qcof if compute_p/qcofactor true
5280       if (compute_pcofactor){
5281 	if (!divrem_(P,D,pmin,modulo,&cof,true,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7,tmp8))
5282 	  return 0;
5283 	convert_back(cof,var,pcof);
5284       }
5285       if (compute_qcofactor){
5286 	if (!divrem_(Q,D,pmin,modulo,&cof,true,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7,tmp8))
5287 	  return 0;
5288 	convert_back(cof,var,qcof);
5289       }
5290       convert_back(D,var,d);
5291       return 1;
5292     }
5293     modred pminmodulo(modulo,pmin);
5294     // multi-dim gcd where pmin does not depend on vars -> Brown's recursive P algorithm
5295     // normalization: leading coeff in Z = 1
5296     std::vector<hashgcd_U> vars_truncated(vars);
5297     vars_truncated.pop_back();
5298     hashgcd_U varxn=vars_truncated.back(),var2=vars.back();
5299     index_t shift_vars,shift_vars_truncated;
5300     if (!find_shift(vars,shift_vars))
5301       return 0; // setsizeerr();
5302     shift_vars_truncated=shift_vars;
5303     shift_vars_truncated.pop_back();
5304     short int shiftxn=shift_vars_truncated.back(),shift2=shift_vars.back();
5305     // Make p and q primitive as polynomials in x1,...,xn-1
5306     // with coeff polynomial in xn
5307     vector< T_unsigned<vector<int>,hashgcd_U> > p(p_orig),q(q_orig),pcont,qcont,dcont,tmp,pcofactor,qcofactor;
5308     vector< vector<int> > pcontxn,qcontxn,dcontxn,pcofcontxn,qcofcontxn;
5309     if (debug_infolevel>20-dim)
5310       CERR << "gcdmod_ext threads " << nthreads << " content begin " << "dim " << dim << " " << CLOCK() << '\n';
5311     if (!pp_mod_last(p,&pmin,modulo,varxn,var2,pcontxn))
5312       return 0;
5313     if (!pp_mod_last(q,&pmin,modulo,varxn,var2,qcontxn))
5314       return 0;
5315     if (!gcdsmallmodpoly_ext(pcontxn,qcontxn,pmin,modulo,dcontxn))
5316       return 0;
5317     if (debug_infolevel>20-dim)
5318       CERR << "gcdmod content in " << "dim " << dim << " " << CLOCK() << '\n';
5319     // Make p and q primitive as polynomial in xn with coeff in x1...xn-1
5320     if (!pp_mod(p,&pmin,modulo,vars,pcont,nthreads))
5321       return 0;
5322     if (!pp_mod(q,&pmin,modulo,vars,qcont,nthreads))
5323       return 0;
5324     mod_gcd_ext(pcont,qcont,vars_truncated,pmin,modulo,dcont,pcofactor,qcofactor,false,false,nthreads); // don't use pv and qv here!
5325     // multiply pcofactor and qcofactor by the initial contents dep. on xn
5326     if (debug_infolevel>20-dim)
5327       CERR << "gcdmod content end " << "dim " << dim << " " << CLOCK() << '\n';
5328     distmult_ext(dcont,dcontxn,dcont,var2,pmin,modulo);
5329     // ready for gcd computation by interpolation with respect to xn
5330     // first find degree of gcd with respect to xn
5331     int pxndeg=degree_xn(p,shiftxn,shift2),qxndeg=degree_xn(q,shiftxn,shift2),gcddeg=0;
5332     vector< vector<int> > pb(pxndeg+1),qb(qxndeg+1),db;
5333     vector<int> b(dim-1),bnext(dim-1);
5334     index_t vzero; // coeff of vzero correspond to zero or non zero
5335     int nzero=1; // Number of zero coeffs
5336     for (int essai=0;essai<2;){
5337       if (debug_infolevel>20-dim)
5338 	CERR << "gcdmod degree? " << essai << " dim " << dim << " " << CLOCK() << '\n';
5339       if (!horner(p,b,vars,pb,modulo) ||
5340 	  !horner(q,b,vars,qb,modulo))
5341 	return false;
5342       for (;;){
5343 	for (int i=0;i<dim-1;++i)
5344 	  bnext[i]=std_rand() % modulo;
5345 	if (!(bnext==b)){ b=bnext; break; }
5346       }
5347       if (int(pb.size())!=pxndeg+1 || int(qb.size())!=qxndeg+1)
5348 	continue;
5349       if (!gcdsmallmodpoly_ext(pb,qb,pmin,modulo,db))
5350 	continue;
5351       int dbdeg=int(db.size())-1;
5352       if (!dbdeg){
5353 	d=dcont;
5354 	if (compute_pcofactor){
5355 	  smallmult(p,pcofactor,pcofactor,pminmodulo,0);
5356 	  vector<int> tmp(invmod(pcofactor.front().g,pminmodulo));
5357 	  mulext(tmp,p_orig.front().g,pmin,modulo);
5358 	  smallmult(tmp,pcofactor,pcofactor,pminmodulo);
5359 	}
5360 	if (compute_qcofactor){
5361 	  smallmult(q,qcofactor,qcofactor,pminmodulo,0);
5362 	  vector<int> tmp(invmod(qcofactor.front().g,pminmodulo));
5363 	  mulext(tmp,q_orig.front().g,pmin,modulo);
5364 	  smallmult(tmp,qcofactor,qcofactor,pminmodulo);
5365 	}
5366 
5367 	return true;
5368       }
5369       if (!essai){ // 1st gcd test
5370 	gcddeg=dbdeg;
5371 	nzero=find_nonzero(db,vzero);
5372 	++essai;
5373 	continue;
5374       }
5375       // 2nd try
5376       if (dbdeg<gcddeg){ // 1st try was unlucky, restart 1st try
5377 	gcddeg=dbdeg;
5378 	nzero=find_nonzero(db,vzero);
5379 	continue;
5380       }
5381       if (dbdeg!=gcddeg)
5382 	  continue;
5383       // Same gcd degree for 1st and 2nd try, keep this degree
5384       index_t tmp;
5385       nzero=find_nonzero(db,tmp);
5386       if (nzero){
5387 	vzero = vzero | tmp;
5388 	// Recompute nzero, it is the number of 0 coeff of vzero
5389 	index_t::const_iterator it=vzero.begin(),itend=vzero.end();
5390 	for (nzero=0;it!=itend;++it){
5391 	  if (!*it)
5392 	    ++nzero;
5393 	}
5394       }
5395       ++essai;
5396     } // end for (essai)
5397     bool pqswap=qxndeg<pxndeg; // swap p and q ?
5398     if (pqswap){
5399       swap(p,q);
5400       swap(pcont,qcont);
5401       swap(pcofactor,qcofactor);
5402       swap(pxndeg,qxndeg);
5403       // swap(pv,qv);
5404 #ifdef BESTA_OS
5405       bool tmpbool=compute_pcofactor;
5406       compute_pcofactor=compute_qcofactor;
5407       compute_qcofactor=tmpbool;
5408       // BESTA DOES NOT LIKE THE FOLLOWING LINE OF CODE
5409 #else
5410       swap(compute_pcofactor,compute_qcofactor);
5411 #endif
5412     }
5413     vector< vector<int> > lcoeffp,lcoeffq,Delta,tmpcont;
5414     hashgcd_U lcoeffpu,lcoeffqu;
5415     if (debug_infolevel>20-dim)
5416       CERR << "gcdmod lcoeff begin " << "dim " << dim << " " << CLOCK() << '\n';
5417     lcoeffpu=lcoeff(p,varxn,var2,lcoeffp);
5418     lcoeffqu=lcoeff(q,varxn,var2,lcoeffq);
5419     if (!gcdsmallmodpoly_ext(lcoeffp,lcoeffq,pmin,modulo,Delta))
5420       return 0;
5421     if (debug_infolevel>20-dim){
5422       CERR << "lcoeff p, q, gcd" << lcoeffp << "," << lcoeffq << "," << Delta << '\n';
5423       CERR << "gcdmod lcoeff end " << "dim " << dim << " " << CLOCK() << '\n';
5424     }
5425     // estimate time for full lift or division try
5426     // size=p.size()+q.size()
5427     // sumdeg=pxndeg+qxndeg
5428     // %age=gcddeg/min(pxndeg,qxndeg)
5429     // %age^dim*(1-%age)^dim*size^2 estimates the time for division try
5430     // gcddeg*size estimates the time for lifting to gcddeg
5431     // sumdeg*size estimates the time for full lifting
5432     // if sumdeg<(gcddeg+%age^dim*(1-%age)^dim*size) do full lifting
5433     int Deltadeg = int(Delta.size())-1,liftdeg=(compute_qcofactor?qxndeg:pxndeg)+Deltadeg;
5434     int gcddeg_plus_delta=gcddeg+Deltadeg;
5435     int liftdeg0=giacmax(liftdeg-gcddeg,gcddeg_plus_delta);
5436     // once liftdeg0 is reached we can replace g/gp/gq computation
5437     // by a check that d*dp=dxn*lcoeff(d*dp)/Delta at alpha
5438     // and d*dq=dxn*lcoeff(d*dq)/lcoeff(qxn) at alpha
5439     int sumdeg = pxndeg+qxndeg;
5440     double percentage = double(gcddeg)/giacmin(pxndeg,qxndeg);
5441     int sumsize = int(p.size()+q.size());
5442     // ? add a malus factor for division
5443     double gcdlift=gcddeg+std::pow(percentage,dim)*std::pow(1-percentage,dim)*sumsize;
5444     bool compute_cof = false; // dim==2 || sumdeg<gcdlift;
5445     // we are now interpolating G=gcd(p,q)*a poly/xn
5446     // such that the leading coeff of G is Delta
5447     index_t pdeg(dim),qdeg(dim),pdegalpha(dim),qdegalpha(dim);
5448     if (debug_infolevel>20-dim)
5449       CERR << "gcdmod ext degree begin " << "dim " << dim << " " << CLOCK() << " compute_cof " << compute_cof << "(" << sumdeg/gcdlift << ")" << '\n';
5450     int ptotaldeg=degree(p,shift_vars,pdeg);
5451     int qtotaldeg=degree(q,shift_vars,qdeg);
5452     if (debug_infolevel>20-dim){
5453       CERR << "pdeg " << pdeg << " " << ptotaldeg << '\n';
5454       CERR << "qdeg " << qdeg << " " << qtotaldeg << '\n';
5455     }
5456     if (debug_infolevel>20-dim)
5457       CERR << "gcdmod degree end " << "dim " << dim << " " << CLOCK() << '\n';
5458     int spdeg=0,sqdeg=0;
5459     for (int i=0;i<dim-1;++i){
5460       spdeg += pdeg[i];
5461       sqdeg += qdeg[i];
5462     }
5463     index_t gdeg(dim-1),delta=index_min(pdeg,qdeg);
5464     delta.pop_back();
5465     int e=0; // number of evaluations
5466     int alpha,alpha1;
5467     if (debug_infolevel>20-dim)
5468       CERR << "gcdmod find alpha dim " << dim << " " << CLOCK() << '\n';
5469     if (debug_infolevel>20-dim)
5470       CERR << " p " << p << " q " << q << '\n';
5471     vector< T_unsigned<vector<int>,hashgcd_U> > palpha,qalpha,dp,dq; // d, dp and dq are the current interpolated values of gcd and cofactors
5472     vector<int> alphav;
5473     vector< vector< T_unsigned<vector<int>,hashgcd_U> > > gcdv,pcofactorv,qcofactorv;
5474     gcd_call_param< vector<int> > gcd_par;
5475     gcd_par.Delta=&Delta;
5476     gcd_par.lcoeffp=&lcoeffp;
5477     gcd_par.lcoeffq=&lcoeffq;
5478     gcd_par.alphav=&alphav;
5479     gcd_par.pv=0;
5480     gcd_par.qv=0;
5481     gcd_par.dim2gcdv=0;
5482     gcd_par.dim2pcofactorv=0;
5483     gcd_par.dim2qcofactorv=0;
5484     gcd_par.p=&p;
5485     gcd_par.q=&q;
5486     gcd_par.gcdv=&gcdv;
5487     gcd_par.pcofactorv=&pcofactorv;
5488     gcd_par.qcofactorv=&qcofactorv;
5489     gcd_par.pdeg=&pdeg;
5490     gcd_par.qdeg=&qdeg;
5491     gcd_par.vars=&vars;
5492     gcd_par.vars_truncated=&vars_truncated;
5493     //gcd_par.shift_vars=&shift_vars;
5494     gcd_par.shift_vars_truncated=&shift_vars_truncated;
5495     gcd_par.compute_cof=compute_cof;
5496     gcd_par.compute_qcofactor=compute_qcofactor;
5497     gcd_par.dim2=false;
5498     gcd_par.pminptr=&pmin;
5499     gcd_par.modulo=modulo;
5500     // Warning: leaving nthreads > 1 is a bad idea if too many allocations
5501     // with lock happen
5502     if (dim>3 && sumsize > modgcd_cachesize ){
5503       gcd_par.nthreads=nthreads;
5504       nthreads=1;
5505     }
5506     else
5507       gcd_par.nthreads=1;
5508     if (nthreads>gcddeg_plus_delta)
5509       nthreads=gcddeg_plus_delta+1;
5510     if (nthreads>1){
5511       int todo=compute_cof?(liftdeg0+1):(gcddeg_plus_delta+1);
5512       double nth=todo/double(nthreads);
5513       // if (nthreads>=4 && (todo%nthreads==0)) nth = (todo+1)/double(nthreads); // keep one proc for a bad prime
5514       nth=std::ceil(nth);
5515       nthreads=int(std::ceil(todo/nth));
5516       if (debug_infolevel>20-dim)
5517 	CERR << "Using " << nthreads << " threads " << nth << " " << todo/nth << '\n';
5518     }
5519     // return -1; // avoid inf loop while not implemented
5520     /* *******************************
5521        BEGIN LOOP
5522        ******************************* */
5523     int gcd_ext_ok=1;
5524     for (alpha=-1;;){
5525       if (gcd_ext_ok!=1)
5526 	return -1;
5527       // First check if we are ready to interpolate
5528       if (!compute_cof && e>gcddeg_plus_delta){
5529 	if (debug_infolevel>20-dim){
5530 	  CERR << "gcdmod before interp " << dim << " clock= " << CLOCK() << gcdv << '\n';
5531 	}
5532 	interpolate(alphav,gcdv,d,var2,modulo);
5533 	vector< T_unsigned<vector<int>,hashgcd_U> > pquo,qquo,tmprem,pD(d);
5534 	pp_mod_last(pD,&pmin,modulo,varxn,var2,tmpcont);
5535 	if (debug_infolevel>20-dim){
5536 	  CERR << "gcdmod pp1mod dim " << dim << " clock= " << CLOCK() << " d " << d << '\n';
5537 	  CERR << "gcdmod alphav " << alphav << '\n' << "gcdv " << gcdv << '\n'
5538 	       << "gcdmod content " << tmpcont << '\n';
5539 	}
5540 	// This removes the polynomial in xn that we multiplied by
5541 	// (it was necessary to know the lcoeff of the interpolated poly)
5542 	if (debug_infolevel>20-dim)
5543 	  CERR << "gcdmod check dim " << dim << " " << CLOCK() << '\n';
5544 	// Now, gcd divides pD for gcddeg+1 values of x1
5545 	// degree(pD)<=degree(gcd)
5546 	// ?CHECK? should we pseudo-divide?
5547 	if (hashdivrem(p,pD,pquo,tmprem,vars,pminmodulo,0,true)==1 && tmprem.empty()){
5548 	  if (hashdivrem(q,pD,qquo,tmprem,vars,pminmodulo,0,true)==1 && tmprem.empty()){
5549 	    smallmult(pD,dcont,d,pminmodulo,0);
5550 	    smallmult(invmod(d.front().g,pminmodulo),d,d,pminmodulo);
5551 	    if (compute_pcofactor){
5552 	      smallmult(pcofactor,pquo,pcofactor,pminmodulo,0);
5553 	      vector<int> tmp(invmod(pcofactor.front().g,pminmodulo));
5554 	      mulext(tmp,p_orig.front().g,pmin,modulo);
5555 	      smallmult(tmp,pcofactor,pcofactor,pminmodulo);
5556 	    }
5557 	    if (compute_qcofactor){
5558 	      smallmult(qcofactor,qquo,qcofactor,pminmodulo,0);
5559 	      vector<int> tmp(invmod(qcofactor.front().g,pminmodulo));
5560 	      mulext(tmp,q_orig.front().g,pmin,modulo);
5561 	      smallmult(tmp,qcofactor,qcofactor,pminmodulo);
5562 	    }
5563 	    if (debug_infolevel>20-dim)
5564 	      CERR << "gcdmod found dim " << dim << " " << CLOCK() << '\n';
5565 	    if (pqswap)
5566 	      swap(pcofactor,qcofactor);
5567 	    return true;
5568 	  } // end if hashdivrem(q,...)
5569 	} // end if hashdivrem(p,...)
5570 	if (debug_infolevel>20-dim)
5571 	  CERR << "Gcdmod bad guess " << '\n';
5572 	// restart
5573 	gcdv.clear(); alphav.clear();
5574 	pcofactorv.clear(); qcofactorv.clear();
5575 	e=0;
5576       } // end if (e>gcddeg+delta)
5577 
5578       if (compute_cof && e>liftdeg0 ){
5579 	// interpolate d and dp
5580 	interpolate(alphav,gcdv,d,var2,modulo);
5581 	if (debug_infolevel>20-dim)
5582 	  CERR << "end interpolate gcd " << CLOCK() << '\n';
5583 	interpolate(alphav,pcofactorv,dp,var2,modulo);
5584 	if (debug_infolevel>20-dim)
5585 	  CERR << "end interpolate p cof " << CLOCK() << '\n';
5586 	// check that d(alpha)*dp(alpha)=palpha with lcoeff adjusted
5587 	// for e<=liftdeg
5588 	vector< T_unsigned<vector<int>,hashgcd_U> > g,gp;
5589 	for (++alpha;e<=liftdeg;++e,++alpha){
5590 	  alpha1=alpha%2?-(alpha+1)/2:alpha/2;
5591 	  while (is_zero(hornermod_ext(lcoeffp,alpha1,modulo))){
5592 	    ++alpha;
5593 	    alpha1=alpha%2?-(alpha+1)/2:alpha/2;
5594 	  }
5595 #ifdef TIMEOUT
5596 	  control_c();
5597 #endif
5598 	  if (ctrl_c || interrupted || alpha>=modulo)
5599 	    return false;
5600 	  int maxtotaldeg=ptotaldeg+1-e;
5601 	  if (!horner(p,alpha1,vars,palpha,modulo,maxtotaldeg))
5602 	    return false;
5603 	  if (debug_infolevel>20-dim)
5604 	    CERR << "gcdmod horner d " << alpha << " dim " << dim << " " << CLOCK() << '\n';
5605 	  if (!horner(d,alpha1,vars,g,modulo,maxtotaldeg))
5606 	    return false;
5607 	  if (debug_infolevel>20-dim)
5608 	    CERR << "gcdmod horner dp " << alpha << " dim " << dim << " " << CLOCK() << '\n';
5609 	  if (!horner(dp,alpha1,vars,gp,modulo,maxtotaldeg))
5610 	    return false;
5611 	  vector<int> tmp;
5612 	  mulext(gp.back().g,g.back().g,pmin,modulo,tmp);
5613 	  invmod(tmp,pminmodulo);
5614 	  mulext(tmp,palpha.back().g,pmin,modulo);
5615 	  smallmult(tmp,gp,gp,pminmodulo);
5616 	  // FIXME is_p_a_times_b
5617 	  if (true
5618 	      // !is_p_a_times_b(palpha,gp,g,vars,modulo,maxtotaldeg)
5619 	      ){
5620 	    // Bad guess, go find some new gcd and interpolate
5621 	    e=liftdeg0+1;
5622 	    break;
5623 	  }
5624 	} // end for ( e loop )
5625 	if (e>liftdeg){
5626 	  // enough evaluation point
5627 	  // divide d,dp,dq by their content in xn
5628 	  pp_mod_last(d,&pmin,modulo,varxn,var2,tmpcont);
5629 	  pp_mod_last(dp,&pmin,modulo,varxn,var2,tmpcont);
5630 	  // check xn degrees of d+dp=degree(pxn), d+dq=degree(qxn)
5631 	  int dxndeg=degree_xn(d,shiftxn,shift2),dpxndeg=degree_xn(dp,shiftxn,shift2);
5632 	  // int dqxndeg=degree_xn(dq,shiftxn,shift2);
5633 	  if ( dxndeg+dpxndeg==pdeg.back() ){
5634 	    smallmult(d,dcont,d,pminmodulo,0);
5635 	    if (compute_pcofactor){
5636 	      smallmult(dp,pcofactor,pcofactor,pminmodulo,0);
5637 	      vector<int> tmp(invmod(pcofactor.front().g,pminmodulo));
5638 	      mulext(tmp,p_orig.front().g,pmin,modulo);
5639 	      smallmult(tmp,pcofactor,pcofactor,pminmodulo);
5640 	    }
5641 	    if (compute_qcofactor){
5642 	      interpolate(alphav,qcofactorv,dq,var2,modulo);
5643 	      pp_mod_last(dq,&pmin,modulo,varxn,var2,tmpcont);
5644 	      smallmult(dq,qcofactor,qcofactor,pminmodulo,0);
5645 	      vector<int> tmp(invmod(qcofactor.front().g,pminmodulo));
5646 	      mulext(tmp,q_orig.front().g,pmin,modulo);
5647 	      smallmult(tmp,qcofactor,qcofactor,pminmodulo);
5648 	    }
5649 	    if (debug_infolevel>20-dim)
5650 	      CERR << "gcdmod end dim " << dim << " " << CLOCK() << '\n';
5651 	    if (pqswap)
5652 	      swap(pcofactor,qcofactor);
5653 	    // divtest=false;
5654 	    return true;
5655 	  }
5656 	  // failure, restart
5657 	  gcdv.clear(); alphav.clear();
5658 	  pcofactorv.clear(); qcofactorv.clear();
5659 	  e=0;
5660 	} // end if (e>lifdeg)
5661       } // end if (compute_cof && e in liftdeg0..liftdeg)
5662 
5663       // *************************************************** //
5664       // Not ready to interpolate, try to eval new points
5665       // *************************************************** //
5666 
5667       for (int thread=0;thread<nthreads;++thread){
5668 	// find a good alpha with respect to leading coeff
5669 	for (;;){
5670 	  ++alpha;
5671 #ifdef TIMEOUT
5672 	  control_c();
5673 #endif
5674 	  if (ctrl_c || interrupted || alpha==modulo){
5675 	    CERR << "Modgcd: no suitable evaluation point" << '\n';
5676 	    return false;
5677 	  }
5678 	  alpha1=alpha%2?-(alpha+1)/2:alpha/2;
5679 	  if (is_zero(hornermod_ext(lcoeffp,alpha1,modulo)) || is_zero(hornermod_ext(lcoeffq,alpha1,modulo)))
5680 	    continue;
5681 	  if (debug_infolevel>20-dim)
5682 	    CERR << "gcdmod eval alpha1=" << alpha1 << " dim " << dim << " " << CLOCK() << '\n';
5683 	  break;
5684 	} // end for (;;)
5685 	// alpha is probably admissible
5686 	// (we will test later if degree of palpha/qalpha wrt x1...xn-1 is max)
5687 	// prepare room for gcd and cofactors
5688 	if (debug_infolevel>20-dim)
5689 	  CERR << "dim " << dim << " palpha " << palpha << " qalpha " << qalpha << '\n' ;
5690 	alphav.push_back(alpha1);
5691 	gcdv.push_back(vector< T_unsigned< vector<int>,hashgcd_U> >(0));
5692 	pcofactorv.push_back(vector< T_unsigned< vector<int>,hashgcd_U> >(0));
5693 	qcofactorv.push_back(vector< T_unsigned< vector<int>,hashgcd_U> >(0));
5694       } // end for (int thread=0;thread<nthreads;++thread)
5695       vector<gcd_call_param<vector<int> > > gcd_call_param_v(nthreads,gcd_par);
5696 #ifdef HAVE_PTHREAD_H
5697       pthread_t tab[nthreads-1];
5698 #endif
5699       for (int thread=0;thread<nthreads;++thread){
5700 	int vpos=int(alphav.size())-(nthreads-thread);
5701 	gcd_call_param_v[thread].vpos=vpos;
5702 	if (thread!=nthreads-1){
5703 	  gcd_call_param_v[thread].pv=0;
5704 	  gcd_call_param_v[thread].qv=0;
5705 	}
5706 #ifdef HAVE_PTHREAD_H
5707 	if (thread==nthreads-1)
5708 	  do_recursive_gcd_ext_call((void *)&gcd_call_param_v[thread]);
5709 	else { // launch gcd computation in a separate thread
5710 	  bool res=pthread_create(&tab[thread],(pthread_attr_t *) NULL,do_recursive_gcd_ext_call,(void *) &gcd_call_param_v[thread]);
5711 	  if (res)
5712 	    do_recursive_gcd_ext_call((void *)&gcd_call_param_v[thread]);
5713 	}
5714 #else
5715 	do_recursive_gcd_ext_call((void *)&gcd_call_param_v[thread]);
5716 #endif
5717       }
5718       // wait for all threads before doing modifications in gcdv and co
5719       for (int thread=0;thread<nthreads-1;++thread){
5720 #ifdef TIMEOUT
5721 	control_c();
5722 #endif
5723 	if (ctrl_c || interrupted)
5724 	  return 0;
5725 	int vpos=int(alphav.size())-(nthreads-thread);
5726 	// wait for thread to finish
5727 #ifdef HAVE_PTHREAD_H
5728 	if (thread!=nthreads-1){
5729 	  void * ptr;
5730 	  pthread_join(tab[thread],&ptr);
5731 	  if (!ptr){
5732 	    gcdv[vpos].clear();
5733 	  }
5734 	  if (gcd_ext_ok==1)
5735 	    gcd_ext_ok=((gcd_call_param<vector<int> > *) ptr)->ext_gcd_ok;
5736 	}
5737 	else {
5738 	  if (gcd_ext_ok==1)
5739 	    gcd_ext_ok=gcd_call_param_v[thread].ext_gcd_ok;
5740 	}
5741 #else
5742 	if (gcd_ext_ok==1)
5743 	  gcd_ext_ok=gcd_call_param_v[thread].ext_gcd_ok;
5744 #endif
5745 	if (gcd_ext_ok!=1)
5746 	  continue; // improve: kill other threads
5747       }
5748       if (gcd_ext_ok!=1)
5749 	continue;
5750       for (int thread=0;thread<nthreads;++thread){
5751 	int vpos=int(alphav.size())-(nthreads-thread);
5752 	// Compare gcd degree in x1..xn-1, 0 means trash this value of alpha1
5753 	int comp=0;
5754 	if (!gcdv[vpos].empty()){
5755 	  degree(gcdv[vpos],shift_vars_truncated,gdeg);
5756 	  comp=compare(gdeg,delta);
5757 	}
5758 	if (comp==-2){
5759 	  // same degrees, add to interpolation
5760 	  /* FIXME SPMOD
5761 	  // Try spmod first
5762 	  if (!compute_cof && nzero){
5763 	    // Add alpha,g
5764 	    if (dim>2 && gcddeg-nzero==e){
5765 	      // We have enough evaluations, let's try SPMOD
5766 	      // Build the matrix, each line has coeffs / vzero
5767 	      vector< vector<int> > m,minverse;
5768 	      for (int j=0;j<=e;++j){
5769 		index_t::const_reverse_iterator it=vzero.rbegin(),itend=vzero.rend();
5770 		vector<int> line;
5771 		for (int p=alphav[j],pp=1;it!=itend;++it,pp=smod(p*pp,modulo)){
5772 		  if (*it)
5773 		    line.push_back(pp);
5774 		}
5775 		reverse(line.begin(),line.end());
5776 		m.push_back(line);
5777 	      }
5778 	      // assume gcd is the vector of non zero coeffs of the gcd in x^n
5779 	      // we have the relation
5780 	      // m*gcd=gcdv
5781 	      // invert m (if invertible)
5782 	      longlong det_mod_p;
5783 	      if (smallmodinv(m,minverse,modulo,det_mod_p) && det_mod_p){
5784 		// hence gcd=minverse*gcdv, where the i-th component of gcd
5785 		// must be "multiplied" by xn^degree_corresponding_vzero[i]
5786 		vector< vector< T_unsigned<int,hashgcd_U> > > minversegcd(e+1);
5787 		for (int j=0;j<=e;++j){
5788 		  for (int k=0;k<=e;++k){
5789 		    vector< T_unsigned<int,hashgcd_U> > tmp(gcdv[k]);
5790 		    smallmult(minverse[j][k],tmp,tmp,modulo);
5791 		    smalladd(minversegcd[j],tmp,minversegcd[j],modulo);
5792 		    // CERR << minversegcd[j] << '\n';
5793 		  }
5794 		}
5795 		vector< T_unsigned<int,hashgcd_U> > trygcd,pquo,qquo,tmprem;
5796 		index_t::const_iterator it=vzero.begin(),itend=vzero.end();
5797 		int deg=itend-it-1;
5798 		for (int j=0;it!=itend;++it,--deg){
5799 		  if (!*it)
5800 		    continue;
5801 		  smallshift(minversegcd[j],deg*var2,minversegcd[j]);
5802 		  smalladd(trygcd,minversegcd[j],trygcd,modulo);
5803 		  ++j;
5804 		}
5805 		// Check if trygcd is the gcd!
5806 		pp_mod(trygcd,0,modulo,varxn,var2,tmpcont);
5807 		if (hashdivrem(p,trygcd,pquo,tmprem,vars,modulo,0,false)==1 && tmprem.empty()){
5808 		  if (hashdivrem(q,trygcd,qquo,tmprem,vars,modulo,0,false)==1 && tmprem.empty()){
5809 		    smallmult(trygcd,dcont,d,modulo,0);
5810 		    smallmult(invmod(d.front().g,modulo),d,d,modulo);
5811 		    if (compute_pcofactor){
5812 		      smallmult(pcofactor,pquo,pcofactor,modulo,0);
5813 		    smallmult(smod(longlong(p_orig.front().g)*invmod(pcofactor.front().g,modulo),modulo),pcofactor,pcofactor);
5814 		    }
5815 		    if (compute_qcofactor){
5816 		      smallmult(qcofactor,qquo,qcofactor,modulo,0);
5817 		      smallmult(smod(longlong(q_orig.front().g)*invmod(qcofactor.front().g,modulo),modulo),qcofactor,qcofactor);
5818 		    }
5819 		    if (debug_infolevel>20-dim)
5820 		      CERR << "gcdmod found dim " << dim << " " << CLOCK() << '\n';
5821 		    if (pqswap)
5822 		      swap(pcofactor,qcofactor);
5823 		    return true;
5824 		  } // end q divisible by trygcd
5825 		} // end p divisible by trygcd
5826 	      } // end m invertible
5827 	    } // end if (dim>2 && )
5828 	  } // end SPMOD
5829 	  */
5830 	  if (debug_infolevel>20-dim)
5831 	    CERR << "gcdmod interp dim " << dim << " " << CLOCK() << '\n';
5832 	  ++e;
5833 	  continue;
5834 	} // end gdeg==delta
5835 	if (comp==0 || comp==-1){
5836 	  if (debug_infolevel>20-dim)
5837 	    CERR << "Bad reduction " << alphav[vpos] << '\n';
5838 	  // bad reduction: all indices of gdeg are >= to delta and gdeg!=delta
5839 	  alphav.erase(alphav.begin()+vpos);
5840 	  gcdv.erase(gcdv.begin()+vpos);
5841 	  pcofactorv.erase(pcofactorv.begin()+vpos);
5842 	  qcofactorv.erase(qcofactorv.begin()+vpos);
5843 	  if (comp==0)
5844 	    continue;
5845 	}
5846 	// previous alpha where bad reduction
5847 	if (debug_infolevel>20-dim && vpos)
5848 	  CERR << "Bads reductions " << alphav[vpos-1] << '\n';
5849 	alphav.erase(alphav.begin(),alphav.begin()+vpos);
5850 	gcdv.erase(gcdv.begin(),gcdv.begin()+vpos);
5851 	pcofactorv.erase(pcofactorv.begin(),pcofactorv.begin()+vpos);
5852 	qcofactorv.erase(qcofactorv.begin(),qcofactorv.begin()+vpos);
5853 	if (comp==-1){
5854 	  e=0;
5855 	  continue;
5856 	}
5857 	// restart everything with this value of alpha
5858 	// this will happen (almost all the time) at first iteration
5859 	delta=gdeg;
5860 	e=1;
5861 	continue;
5862       } // end for (int thread=0;thread<nthreads;++thread)
5863     } // end for (alpha=-1;;)
5864 #endif // NO_TEMPLATE_MULTGCD
5865   }
5866 
ichinrem_ext(const vecteur & v,const gen & g,const gen & modulo,const gen & pimod)5867   static gen ichinrem_ext(const vecteur & v,const gen & g,const gen & modulo,const gen & pimod){
5868     if (g.type!=_VECT){
5869       vecteur w(v);
5870       iterateur it=w.begin(),itend=w.end(),it_;
5871       it_=itend-1;
5872       for (;it!=itend;++it){
5873 	*it=ichinrem(*it,(it==it_?g:0),modulo,pimod);
5874       }
5875       return w;
5876     }
5877     vecteur & w = *g._VECTptr;
5878     vecteur::const_reverse_iterator it=v.rbegin(),itend=v.rend();
5879     vecteur::reverse_iterator jt=w.rbegin(),jtend=w.rend();
5880     vecteur res;
5881     for (;it!=itend && jt!=jtend;++it,++jt){
5882       res.push_back(ichinrem(*it,*jt,modulo,pimod));
5883     }
5884     for (;it!=itend;++it)
5885       res.push_back(ichinrem(*it,0,modulo,pimod));
5886     for (;jt!=jtend;++jt)
5887       res.push_back(ichinrem(0,*jt,modulo,pimod));
5888     reverse(res.begin(),res.end());
5889     return res;
5890   }
5891 
ichinrem_ext(const vector<T_unsigned<vecteur,hashgcd_U>> & p_orig,const gen & modulo,vector<T_unsigned<gen,hashgcd_U>> & p,const gen & pimod)5892   static void ichinrem_ext(const vector< T_unsigned<vecteur,hashgcd_U> > & p_orig,const gen & modulo,vector< T_unsigned<gen,hashgcd_U> > & p,const gen & pimod){
5893     vector< T_unsigned<gen,hashgcd_U> > q;
5894     vector< T_unsigned< vecteur,hashgcd_U> >::const_iterator it=p_orig.begin(),itend=p_orig.end();
5895     vector< T_unsigned<gen,hashgcd_U> >::const_iterator jt=p.begin(),jtend=p.end();
5896     q.reserve(jtend-jt);
5897     for (;it!=itend && jt!=jtend;){
5898       if (it->u==jt->u){
5899 	const vecteur & tmp=it->g;
5900 	q.push_back(T_unsigned<gen,hashgcd_U>(ichinrem_ext(tmp,jt->g,modulo,pimod),it->u));
5901 	++it; ++jt;
5902 	continue;
5903       }
5904       if (it->u<jt->u){
5905 	q.push_back(T_unsigned<gen,hashgcd_U>(ichinrem_ext(vecteur(0),jt->g,modulo,pimod),jt->u));
5906 	++jt;
5907       }
5908       else {
5909 	const vecteur & tmp=it->g;
5910 	q.push_back(T_unsigned<gen,hashgcd_U>(ichinrem_ext(tmp,0,modulo,pimod),it->u));
5911 	++it;
5912       }
5913     }
5914     for (;it!=itend;++it){
5915       const vecteur & tmp=it->g;
5916       q.push_back(T_unsigned<gen,hashgcd_U>(ichinrem_ext(tmp,0,modulo,pimod),it->u));
5917     }
5918     for (;jt!=jtend;++jt)
5919       q.push_back(T_unsigned<gen,hashgcd_U>(ichinrem_ext(vecteur(0),jt->g,modulo,pimod),jt->u));
5920     swap(p,q);
5921   }
5922 
5923   // add pmin extension to all vecteurs inside p
make_ext(vector<T_unsigned<gen,hashgcd_U>> & p,const gen & pmin)5924   static void make_ext(vector< T_unsigned<gen,hashgcd_U> > &p,const gen & pmin){
5925     vector< T_unsigned<gen,hashgcd_U> >::iterator jt=p.begin(),jtend=p.end();
5926     for (;jt!=jtend;++jt){
5927       if (jt->g.type==_VECT)
5928 	jt->g=algebraic_EXTension(jt->g,pmin);
5929     }
5930   }
5931 
fracmod(const vector<T_unsigned<gen,hashgcd_U>> & p,const gen & modulo,vector<T_unsigned<gen,hashgcd_U>> & q)5932   static bool fracmod(const vector< T_unsigned<gen,hashgcd_U> > &p,const gen & modulo,vector< T_unsigned<gen,hashgcd_U> > & q){
5933     q=p;
5934     gen tmp;
5935     vector< T_unsigned<gen,hashgcd_U> >::iterator jt=q.begin(),jtend=q.end();
5936     for (;jt!=jtend;++jt){
5937       if (!fracmod(jt->g,modulo,tmp))
5938 	return false;
5939       jt->g=tmp;
5940     }
5941     return true;
5942   }
5943 
5944   // should be called from gausspol.cc in gcdheu after monomial packing like in modpoly.cc gcd_modular
gcd_ext(const vector<T_unsigned<gen,hashgcd_U>> & p_orig,const vector<T_unsigned<gen,hashgcd_U>> & q_orig,vector<T_unsigned<gen,hashgcd_U>> & d,vector<T_unsigned<gen,hashgcd_U>> & pcofactor,vector<T_unsigned<gen,hashgcd_U>> & qcofactor,const std::vector<hashgcd_U> & vars,bool compute_cofactors,int nthreads)5945   bool gcd_ext(const vector< T_unsigned<gen,hashgcd_U> > & p_orig,const vector< T_unsigned<gen,hashgcd_U> > & q_orig,vector< T_unsigned<gen,hashgcd_U> > & d, vector< T_unsigned<gen,hashgcd_U> > & pcofactor, vector< T_unsigned<gen,hashgcd_U> > & qcofactor,const std::vector<hashgcd_U> & vars, bool compute_cofactors,int nthreads){
5946 #ifdef NO_TEMPLATE_MULTGCD
5947     return false;
5948 #else
5949     // find extension
5950     compute_cofactors=false;
5951     gen coefft;
5952     int tp=is_integer(p_orig,coefft),tq=is_integer(q_orig,coefft);
5953     if (!tp || !tq)
5954       return false;
5955     if (tp<3 && tq<3)
5956       return false;
5957     if (tp==3 && tq==2)
5958       tp=4;
5959     if (tq==3 && tp==2)
5960       tp=4;
5961     if (tq>tp)
5962       tp=tq;
5963     index_t shift_vars;
5964     if (!find_shift(vars,shift_vars))
5965       return false;
5966     coefft=*(coefft._EXTptr+1);
5967     if (coefft.type!=_VECT || coefft._VECTptr->empty() || !is_integer_vecteur(*coefft._VECTptr))
5968       return false;
5969     vecteur & pminv=*coefft._VECTptr;
5970     gen pmin0=pminv.front();
5971     gen m=536871000,pimod=1;
5972     gen lcoeffp=p_orig.front().g,lcoeffq=q_orig.front().g;
5973     d.clear();
5974     pcofactor.clear();
5975     qcofactor.clear();
5976     vector< T_unsigned<vecteur,hashgcd_U> > p,q,g,pcof,qcof;
5977     index_t pdeg,qdeg,pdegmod,qdegmod,gdegmod,gdegmod2,gdeg;
5978     degree(p_orig,shift_vars,pdeg);
5979     degree(q_orig,shift_vars,qdeg);
5980     gdeg=index_min(pdeg,qdeg);
5981     if (tp==4){
5982       // return false;
5983       vector< T_unsigned<vecteur,hashgcd_U> > p1,q1,g1,pcof1,qcof1,p2,q2,g2,pcof2,qcof2;
5984       // tp==4, use primes == 1 % 4, find gcds replacing i by both
5985       // sqrts of -1 modulo the primes, ichinrem
5986       for (int n=0;;n++){
5987 	m=nextprime(m+1);
5988 #ifdef TIMEOUT
5989 	control_c();
5990 #endif
5991 	if (ctrl_c || interrupted || m.type!=_INT_)
5992 	  return false;
5993 	int modulo=m.val;
5994 	// computing gcd in Z[i]: use a modulo =1[4], find gcd for both roots of -1 mod modulo
5995 	if (modulo%4==3)
5996 	  continue;
5997 	// min poly mod modulo, coeffs should not contain i==sqrt(-1)
5998 	if (is_zero(smod(pmin0,modulo)))
5999 	  continue;
6000 	if (debug_infolevel>(int)shift_vars.size())
6001 	  CERR << "Modular algebraic extension gcd " << modulo << '\n';
6002 	vecteur pmin;
6003 	pmin.reserve(pminv.size());
6004 	const_iterateur it=pminv.begin(),itend=pminv.end();
6005 	for (;it!=itend;++it){
6006 	  pmin.push_back(smod(*it,modulo));
6007 	}
6008 	// find square root of -1
6009 	int i=modsqrtminus1(modulo);
6010 	gen lp1=complex_smod_ext(lcoeffp,i,modulo),lp2=complex_smod_ext(lcoeffp,-i,modulo);
6011 	gen lq1=complex_smod_ext(lcoeffq,i,modulo),lq2=complex_smod_ext(lcoeffq,-i,modulo);
6012 	if (is_zero(lp1) || is_zero(lq1) || is_zero(lp2) || is_zero(lq2))
6013 	  continue;
6014 	if (!complex_smod_ext(p_orig,i,modulo,p1))
6015 	  return false; // setsizeerr();
6016 	degree(p1,shift_vars,pdegmod);
6017 	if (pdegmod!=pdeg)
6018 	  continue;
6019 	if (!complex_smod_ext(q_orig,i,modulo,q1))
6020 	  return false; // setsizeerr();
6021 	degree(q1,shift_vars,qdegmod);
6022 	if (qdegmod!=qdeg)
6023 	  continue;
6024 	if (!complex_smod_ext(p_orig,-i,modulo,p2))
6025 	  return false; // setsizeerr();
6026 	degree(p2,shift_vars,pdegmod);
6027 	if (pdegmod!=pdeg)
6028 	  continue;
6029 	if (!complex_smod_ext(q_orig,-i,modulo,q2))
6030 	  return false; // setsizeerr();
6031 	degree(q2,shift_vars,qdegmod);
6032 	if (qdegmod!=qdeg)
6033 	  continue;
6034 	int res=gcd_ext(p1,q1,vars,pmin,modulo,g1,pcof1,qcof1,compute_cofactors,compute_cofactors,nthreads);
6035 	// ?FIXME? check that g1, pcof1, qcof1 are normalized
6036 #ifdef TIMEOUT
6037 	control_c();
6038 #endif
6039 	if (res==-1 || ctrl_c || interrupted)
6040 	  return false;
6041 	if (!res)
6042 	  continue;
6043 	res=gcd_ext(p2,q2,vars,pmin,modulo,g2,pcof2,qcof2,compute_cofactors,compute_cofactors,nthreads);
6044 #ifdef TIMEOUT
6045 	control_c();
6046 #endif
6047 	if (res==-1 || ctrl_c || interrupted)
6048 	  return false;
6049 	if (!res)
6050 	  continue;
6051 	// CERR << p1 << " " << q1 << " " << g1 << '\n' << p2 << " " << q2 << " " << g2 << '\n' ;
6052 	// IMPROVE? use a map for modulo -> g1,g2,etc.
6053 	// and do chinese remaindering for poly having the same lcoeff
6054 	degree(g1,shift_vars,gdegmod);
6055 	degree(g2,shift_vars,gdegmod2);
6056 	if (gdegmod2!=gdegmod)
6057 	  continue;
6058 	if (gdegmod.front()>gdeg.front()) // unlucky prime
6059 	  continue;
6060 	int cmp=compare(gdegmod,gdeg);
6061 	if (cmp==-1){
6062 	  // full restart
6063 	  d.clear();
6064 	  pcofactor.clear();
6065 	  qcofactor.clear();
6066 	  pimod=1;
6067 	  continue;
6068 	}
6069 	if (cmp!=-2){
6070 	  // restart with this gcd
6071 	  gdeg=gdegmod;
6072 	  d.clear();
6073 	  pcofactor.clear();
6074 	  qcofactor.clear();
6075 	  pimod=1;
6076 	}
6077 	complex_ichinrem_ext(g1,g2,i,modulo,d,pimod);
6078 	if (compute_cofactors){
6079 	  complex_ichinrem_ext(pcof1,pcof2,i,modulo,pcofactor,pimod);
6080 	  complex_ichinrem_ext(qcof1,qcof2,i,modulo,qcofactor,pimod);
6081 	}
6082 	pimod = modulo * pimod;
6083 	// rational reconstruction and division test
6084 	vector< T_unsigned<gen,hashgcd_U> > dtest,pcofactortest,qcofactortest,pquo,qquo,rem;
6085 	fracmod(d,pimod,dtest);
6086 	lcmdeno(dtest);
6087 	gen tmp;
6088 	ppz(dtest,tmp,true);
6089 	make_ext(dtest,coefft); // make extensions
6090 	if (compute_cofactors){
6091 	  fracmod(pcofactor,pimod,pcofactortest);
6092 	  fracmod(qcofactor,pimod,qcofactortest);
6093 	  lcmdeno(pcofactortest);
6094 	  ppz(pcofactortest,tmp,true);
6095 	  lcmdeno(qcofactortest);
6096 	  ppz(qcofactortest,tmp,true);
6097 	  // lcoeff(p)*dtest*pcofactortest =? p*lcoeff(dtest)*lcoeff(pcofactortest)
6098 	  // this is true mod pimod, check sizes
6099 	  // If AxB=C mod m,Pmin(theta)
6100 	  // then A*B-C=mD mod Pmin(theta)
6101 	  // The size of coeffs of A*B-C is <=
6102 	  // <= |A|*|B|* min(size(A),size(B)) * (degpmin+1) +|C|
6103 	  // but division by Pmin(theta) may enlarge the remainder
6104 	  // by a multiplication by ((degpmin+1)*|Pmin|)^(degpmin-1)
6105 	  // remove denominators and integer content
6106 	  gen lcoeffdpcof=dtest.front().g*pcofactortest.front().g;
6107 	  simplify(lcoeffp,lcoeffdpcof);
6108 	  gen lcoeffdqcof=dtest.front().g*qcofactortest.front().g;
6109 	  simplify(lcoeffq,lcoeffdqcof);
6110 	  gen maxp=max(p_orig,context0),maxq=max(q_orig,context0),maxpcof=max(pcofactortest,context0),maxqcof=max(qcofactortest,context0),maxd=max(dtest,context0);
6111 	  gen maxpmin=_max(coefft,context0),degpmin=int(pminv.size()-1);
6112 	  if (is_undef(maxpmin)) return false;
6113 	  gen multpmin=pow((degpmin+1)*maxpmin,degpmin,context0);
6114 	  gen test1=lcoeffdpcof*maxp+lcoeffp*maxd*maxpcof*gen(int(std::min(dtest.size(),pcofactortest.size())))*(degpmin+1)*multpmin;
6115 	  gen test2=lcoeffdqcof*maxq+lcoeffq*maxd*maxqcof*gen(int(std::min(dtest.size(),qcofactortest.size())))*(degpmin+1)*multpmin;
6116 	  if (is_strictly_greater(pimod,test1,context0) && is_strictly_greater(pimod,test2,context0)){
6117 	    // leave d unchanged but adjust pcofactor and qcofactor
6118 	    swap(d,dtest);
6119 	    smallmult(lcoeffp/lcoeffdpcof,pcofactortest,pcofactor);
6120 	    smallmult(lcoeffq/lcoeffdqcof,qcofactortest,qcofactor);
6121 	    return true;
6122 	  }
6123 	}
6124 	if (hashdivrem(p_orig,dtest,pquo,rem,vars,0 /* reduce */,0/*qmax*/,true)==1 && rem.empty()){
6125 	  if (hashdivrem(q_orig,dtest,qquo,rem,vars,0 /* reduce */,0/*qmax*/,true)==1 && rem.empty()){
6126 	    // FIXME normalize d
6127 	    swap(pcofactor,pquo);
6128 	    swap(qcofactor,qquo);
6129 	    swap(d,dtest);
6130 	    return true;
6131 	  }
6132 	}
6133       }
6134     }
6135     // begin loop on modulo
6136     vector< T_unsigned<gen,hashgcd_U> > dtestold;
6137     for (int n=0;;n++){
6138       m=nextprime(m+1);
6139 #ifdef TIMEOUT
6140       control_c();
6141 #endif
6142       if (ctrl_c || interrupted || m.type!=_INT_)
6143 	return false;
6144       int modulo=m.val;
6145       if (debug_infolevel>(int)shift_vars.size())
6146 	CERR << "Modular algebraic extension gcd " << modulo << '\n';
6147       // min poly mod modulo
6148       if (is_zero(smod(pmin0,modulo)))
6149 	continue;
6150       vecteur pmin;
6151       pmin.reserve(pminv.size());
6152       const_iterateur it=pminv.begin(),itend=pminv.end();
6153       for (;it!=itend;++it){
6154 	pmin.push_back(smod(*it,modulo));
6155       }
6156       // reduce mod m
6157       if (!smod_ext(p_orig,m.val,p) || !smod_ext(q_orig,m.val,q))
6158 	return false;
6159       // check degrees of p and q mod modulo
6160       degree(p,shift_vars,pdegmod);
6161       if (pdegmod!=pdeg)
6162 	continue;
6163       degree(q,shift_vars,qdegmod);
6164       if (qdegmod!=qdeg)
6165 	continue;
6166       // if one lcoeff of p/q is not invertible mod modulo
6167       // then it won't be when variables of p or q are evaluated
6168       // hence checking in dim 1 is sufficient
6169       if (debug_infolevel>0)
6170 	CERR << CLOCK()*1e-6 << " begin gcd_ext mod " << modulo <<"," << pmin << '\n';
6171       int res=gcd_ext(p,q,vars,pmin,modulo,g,pcof,qcof,compute_cofactors,compute_cofactors,nthreads);
6172       if (debug_infolevel>0)
6173 	CERR << CLOCK()*1e-6 << " end gcd_ext mod " << modulo <<"," << pmin << '\n';
6174 #ifdef TIMEOUT
6175       control_c();
6176 #endif
6177       if (ctrl_c || interrupted || res==-1)
6178 	return false;
6179       if (!res)
6180 	continue;
6181       // ?FIXME? check that g is normalized to have lcoeff==1
6182       // IMPROVE? use a map for modulo -> lcoeff -> g, pcof, qcof, pimodulo
6183       // and chinese remainder with modulos having the same lcoeff
6184       degree(g,shift_vars,gdegmod);
6185       if (gdegmod.front()>gdeg.front()) // unlucky prime
6186 	continue;
6187       // Check with respect to other variables
6188       // N.B.: it could be faster to store all g,pcof,qcof
6189       // to avoid a full restart each time an unlucky content is reached
6190       // Here we must have sufficiently successive primes
6191       // that do not have unlucky content
6192       int cmp=compare(gdegmod,gdeg);
6193       if (cmp==-1){
6194 	// full restart
6195 	d.clear();
6196 	pcofactor.clear();
6197 	qcofactor.clear();
6198 	pimod=1;
6199 	continue;
6200       }
6201       if (cmp!=-2){
6202 	// restart with this gcd
6203 	gdeg=gdegmod;
6204 	d.clear();
6205 	pcofactor.clear();
6206 	qcofactor.clear();
6207 	pimod=1;
6208       }
6209       // Same degrees
6210       // chinese remainder of g and d
6211       ichinrem_ext(g,modulo,d,pimod);
6212       if (compute_cofactors){
6213 	ichinrem_ext(pcof,modulo,pcofactor,pimod);
6214 	ichinrem_ext(qcof,modulo,qcofactor,pimod);
6215 	CERR << "g " << d << '\n';
6216 	CERR << "pcof " << pcofactor << '\n';
6217 	CERR << "qcof " << qcofactor << '\n';
6218       }
6219       pimod = modulo * pimod;
6220       // rational reconstruction and division test
6221       vector< T_unsigned<gen,hashgcd_U> > dtest,pcofactortest,qcofactortest,pquo,qquo,rem;
6222       fracmod(d,pimod,dtest);
6223       lcmdeno(dtest);
6224       gen tmp;
6225       ppz(dtest,tmp,true);
6226       make_ext(dtest,coefft); // make extensions
6227       if (0 && compute_cofactors){
6228 	// DISABLED: I don't know how equality mod m could be translated
6229 	// (absolute values of algebraic extension)
6230 	fracmod(pcofactor,pimod,pcofactortest);
6231 	fracmod(qcofactor,pimod,qcofactortest);
6232 	lcmdeno(pcofactortest);
6233 	ppz(pcofactortest,tmp,true);
6234 	lcmdeno(qcofactortest);
6235 	ppz(qcofactortest,tmp,true);
6236 	// lcoeff(p)*dtest*pcofactortest =? p*lcoeff(dtest)*lcoeff(pcofactortest)
6237 	// this is true mod pimod, check sizes
6238 	// If AxB=C mod m,Pmin(theta)
6239 	// then A*B-C=mD mod Pmin(theta)
6240 	// The size of coeffs of A*B-C is <=
6241 	// <= |A|*|B|* min(size(A),size(B)) * (degpmin+1) +|C|
6242 	// but division by Pmin(theta) may enlarge the remainder
6243 	// by a multiplication by ((degpmin+1)*|Pmin|)^(degpmin-1)
6244 	// remove denominators and integer content
6245 	gen lcoeffdpcof=dtest.front().g*pcofactortest.front().g;
6246 	simplify(lcoeffp,lcoeffdpcof);
6247 	gen lcoeffdqcof=dtest.front().g*qcofactortest.front().g;
6248 	simplify(lcoeffq,lcoeffdqcof);
6249 	gen maxp=max(p_orig,context0);
6250 	gen maxq=max(q_orig,context0);
6251 	gen maxpcof=max(pcofactortest,context0);
6252 	gen maxqcof=max(qcofactortest,context0);
6253 	gen maxd=max(dtest,context0);
6254 	gen maxpmin=_max(coefft,context0),degpmin=int(pminv.size()-1);
6255 	if (is_undef(maxpmin)) return false;
6256 	gen multpmin=pow((degpmin+1)*maxpmin,degpmin,context0);
6257 	gen test1=lcoeffdpcof*maxp+lcoeffp*maxd*maxpcof*gen(int(std::min(dtest.size(),pcofactortest.size())))*(degpmin+1)*multpmin;
6258 	gen test2=lcoeffdqcof*maxq+lcoeffq*maxd*maxqcof*gen(int(std::min(dtest.size(),qcofactortest.size())))*(degpmin+1)*multpmin;
6259 	if (is_strictly_greater(pimod,test1,context0) && is_strictly_greater(pimod,test2,context0)){
6260 	  // leave d unchanged but adjust pcofactor and qcofactor
6261 	  swap(d,dtest);
6262 	  smallmult(lcoeffp/lcoeffdpcof,pcofactortest,pcofactor);
6263 	  smallmult(lcoeffq/lcoeffdqcof,qcofactortest,qcofactor);
6264 	  return true;
6265 	}
6266       }
6267       // This division might take a very long time if not successful
6268       // Make it only when we are sure (might be improved)
6269       if (dtest==dtestold){
6270 	if (debug_infolevel>0)
6271 	  CERR << CLOCK()*1e-6 << " gcd_ext checking gcd" << '\n';
6272 	if (hashdivrem(p_orig,dtest,pquo,rem,vars,0 /* reduce */,0/*qmax*/,true)==1 && rem.empty()){
6273 	  // CERR << "p " << p_orig << '\n' << "dtest " << dtest << '\n' << "quo" << pquo << '\n';
6274 	  if (debug_infolevel>0)
6275 	    CERR << CLOCK()*1e-6 << " gcd_ext checking gcd 1st test ok" << '\n';
6276 	  if (hashdivrem(q_orig,dtest,qquo,rem,vars,0 /* reduce */,0/*qmax*/,true)==1 && rem.empty()){
6277 	    // CERR << "q " << q_orig << '\n' << "dtest " << dtest << '\n' << "quo" << qquo << '\n';
6278 	    if (debug_infolevel>0)
6279 	      CERR << CLOCK()*1e-6 << " gcd_ext checking gcd 2nd test ok" << '\n';
6280 	    swap(pcofactor,pquo);
6281 	    swap(qcofactor,qquo);
6282 	    swap(d,dtest);
6283 	    return true;
6284 	  }
6285 	}
6286       }
6287       dtestold=dtest;
6288     }
6289 #endif // NO_TEMPLATE_MULTGCD
6290   }
6291 
6292 #ifndef NO_NAMESPACE_GIAC
6293 } // namespace giac
6294 #endif // ndef NO_NAMESPACE_GIAC
6295 
6296