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=Δ
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=Δ
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