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