1 #include "CoCoA/DUPFp.H" 2 3 #include "CoCoA/SparsePolyIter.H" 4 #include "CoCoA/SparsePolyOps-RingElem.H" 5 //#include "CoCoA/SparsePolyRing.H" // from SparsePolyOps-RingElem.H 6 #include "CoCoA/error.H" 7 #include "CoCoA/utils.H" 8 // Next is for STOPGAP impl of factor 9 #include "TmpFactorDir/DUPFFfactor.h" 10 11 #include <algorithm> 12 using std::max; 13 #include <iostream> 14 #include <numeric> 15 using std::inner_product; 16 #include <vector> 17 using std::vector; 18 19 namespace CoCoA 20 { 21 DUPFp(long maxdeg,const SmallFpImpl & arith)22 DUPFp::DUPFp(long maxdeg, const SmallFpImpl& arith): 23 myArith(arith) 24 { myCoeffs.reserve(maxdeg+1); } 25 26 27 //inline void swap(DUPFp& a, DUPFp& b) { std::swap(a.myCoeffs, b.myCoeffs); } 28 29 AssignZero(DUPFp & f)30 void AssignZero(DUPFp& f) 31 { 32 f.myCoeffs.clear(); 33 } 34 35 AssignOne(DUPFp & f)36 void AssignOne(DUPFp& f) 37 { 38 f.myCoeffs.clear(); 39 f.myCoeffs.push_back(one(SmallFp)); 40 } 41 42 IsZero(const DUPFp & f)43 bool IsZero(const DUPFp& f) 44 { 45 return f.myCoeffs.empty(); 46 } 47 48 deg(const DUPFp & f)49 long deg(const DUPFp& f) // deg(0) = -1 50 { 51 return len(f.myCoeffs)-1; 52 } 53 54 FixDeg(DUPFp & f)55 void FixDeg(DUPFp& f) 56 { 57 long d = len(f.myCoeffs); 58 while (--d >= 0 && IsZero(f.myCoeffs[d])) {} 59 f.myCoeffs.resize(d+1); 60 } 61 62 LC(const DUPFp & f)63 SmallFpImpl::value LC(const DUPFp& f) 64 { 65 if (f.myCoeffs.empty()) return zero(SmallFp); 66 return f.myCoeffs.back(); 67 } 68 69 MakeMonic(DUPFp & f)70 void MakeMonic(DUPFp& f) 71 { 72 if (IsZero(f)) CoCoA_THROW_ERROR(ERR::DivByZero, "MakeMonic"); 73 f /= LC(f); 74 } 75 monic(const DUPFp & f)76 DUPFp monic(const DUPFp& f) 77 { 78 if (IsZero(f)) CoCoA_THROW_ERROR(ERR::DivByZero, "monic"); 79 return f/LC(f); 80 } 81 82 83 DUPFp operator*(const DUPFp& f, SmallFpImpl::value c) 84 { 85 const SmallFpImpl& ModP = f.myArith; 86 if (IsZero(c)) return DUPFp(0, ModP); 87 if (IsOne(c)) return f; 88 const long d = deg(f); 89 DUPFp ans(d, ModP); 90 ans.myCoeffs.resize(d+1); 91 for (long i=0; i <= d; ++i) 92 ans.myCoeffs[i] = ModP.myMul(f.myCoeffs[i], c); 93 // ***ASSUME*** ModP is a field, o/w need to call FixDeg 94 return ans; 95 } 96 97 DUPFp& operator*=(DUPFp& f, SmallFpImpl::value c) 98 { 99 const SmallFpImpl& ModP = f.myArith; 100 if (IsZero(c)) 101 { 102 f.myCoeffs.clear(); 103 return f; 104 } 105 if (IsOne(c)) return f; 106 const long N = len(f.myCoeffs); 107 for (long i=0; i < N; ++i) 108 f.myCoeffs[i] = ModP.myMul(f.myCoeffs[i], c); 109 // ***ASSUME*** ModP is a field, o/w need to call FixDeg 110 return f; 111 } 112 113 114 DUPFp operator/(const DUPFp& f, SmallFpImpl::value c) 115 { 116 const SmallFpImpl& ModP = f.myArith; 117 if (IsZero(c)) 118 CoCoA_THROW_ERROR(ERR::DivByZero, "op/(DUPFp,n)"); 119 if (IsOne(c)) return f; 120 return f * ModP.myRecip(c); 121 } 122 123 124 DUPFp& operator/=(DUPFp& f, SmallFpImpl::value c) 125 { 126 const SmallFpImpl& ModP = f.myArith; 127 if (IsZero(c)) 128 CoCoA_THROW_ERROR(ERR::DivByZero, "op/=(DUPFp,n)"); 129 130 if (IsOne(c)) return f; 131 f *= ModP.myRecip(c); 132 // const SmallFpImpl::value crecip = ModP.myRecip(c); 133 // const long N = len(f.myCoeffs); 134 // for (long i=0; i < N; ++i) 135 // f.myCoeffs[i] = ModP.myMul(f.myCoeffs[i], crecip); 136 return f; 137 } 138 139 add(DUPFp & lhs,const DUPFp & f,const DUPFp & g)140 void add(DUPFp& lhs, const DUPFp& f, const DUPFp& g) 141 { 142 CoCoA_ASSERT(f.myArith == g.myArith); 143 const SmallFpImpl& ModP = f.myArith; 144 const long df = deg(f); 145 const long dg = deg(g); 146 const vector<SmallFpImpl::value>& F = f.myCoeffs; 147 const vector<SmallFpImpl::value>& G = g.myCoeffs; 148 // Compute deg of ans in d... 149 long d = max(df, dg); 150 if (df == dg) 151 while (d >= 0 && IsZero(ModP.myAdd(F[d], G[d]))) 152 --d; 153 154 vector<SmallFpImpl::value>& H = lhs.myCoeffs; 155 H.resize(d+1); // NB safe even if lhs aliases f or g! 156 if (d < 0) return; 157 for (; d>df; --d) H[d] = G[d]; 158 for (; d>dg; --d) H[d] = F[d]; 159 for (; d>=0; --d) 160 H[d] = ModP.myAdd(F[d], G[d]); 161 } 162 163 164 DUPFp operator+(const DUPFp& f, const DUPFp& g) 165 { 166 DUPFp ans(0, f.myArith); 167 add(ans, f, g); 168 return ans; 169 } 170 171 sub(DUPFp & lhs,const DUPFp & f,const DUPFp & g)172 void sub(DUPFp& lhs, const DUPFp& f, const DUPFp& g) 173 { 174 CoCoA_ASSERT(f.myArith == g.myArith); 175 const SmallFpImpl& ModP = f.myArith; 176 const long df = deg(f); 177 const long dg = deg(g); 178 const vector<SmallFpImpl::value>& F = f.myCoeffs; 179 const vector<SmallFpImpl::value>& G = g.myCoeffs; 180 // Compute deg of ans in d... 181 long d = max(df, dg); 182 if (df == dg) 183 while (d >= 0 && F[d] == G[d]) 184 --d; 185 186 vector<SmallFpImpl::value>& H = lhs.myCoeffs; 187 H.resize(d+1); // NB safe even if lhs aliases f or g 188 if (d < 0) return; 189 for (; d>df; --d) H[d] = ModP.myNegate(G[d]); 190 for (; d>dg; --d) H[d] = F[d]; 191 for (; d>=0; --d) 192 H[d] = ModP.mySub(F[d], G[d]); 193 } 194 195 196 DUPFp operator-(const DUPFp& f, const DUPFp& g) 197 { 198 DUPFp ans(0, f.myArith); 199 sub(ans, f, g); 200 return ans; 201 } 202 203 mul(DUPFp & lhs,const DUPFp & f,const DUPFp & g)204 void mul(DUPFp& lhs, const DUPFp& f, const DUPFp& g) 205 { 206 typedef SmallFpImpl::value FpElem; 207 CoCoA_ASSERT(&lhs != &f); 208 CoCoA_ASSERT(&lhs != &g); 209 CoCoA_ASSERT(f.myArith == g.myArith); 210 const SmallFpImpl& ModP = f.myArith; 211 const long df = deg(f); 212 const long dg = deg(g); 213 const vector<FpElem>& F = f.myCoeffs; 214 const vector<FpElem>& G = g.myCoeffs; 215 216 if (IsZero(f) || IsZero(g)) 217 { 218 AssignZero(lhs); 219 return; 220 } 221 if (df < dg) { mul(lhs, g, f); return; } 222 // Compute deg of ans in d... 223 const long d = df + dg; 224 vector<FpElem>& H = lhs.myCoeffs; 225 H.clear(); 226 H.resize(d+1); 227 228 const long MaxIters = ModP.myMaxIters(); 229 230 // This impl is about 50% slower than the one after it 231 // long count = 0; 232 // long pause = 2*MaxIters; 233 // for (long i=0; i <= dg; ++i) 234 // { 235 // if (G[i] == 0) continue; 236 // ++count; 237 // for (long j=0; j <= df; ++j) 238 // H[i+j] += F[j]*G[i]; 239 // if (count != pause) continue; 240 // pause += MaxIters; 241 // const long stop = df-MaxIters; 242 // for (long j=1; j <= stop; ++j) 243 // H[i+j] = ModP.myReduceQ(H[i+j]); 244 // } 245 // for (long i=0; i <=d; ++i) 246 // H[i] = ModP.myReduce(H[i]); 247 248 const long BlockSize = (dg<=2*MaxIters) ? 0 : MaxIters; 249 for (long k=0; k <= d; ++k) 250 { 251 const FpElem *flast, *fi, *gj; 252 if (k >= df) flast = &F[df]; else flast = &F[k]; 253 if (k >= dg) { fi = &F[k-dg]; gj = &G[dg]; } 254 else { fi = &F[0]; gj = &G[k]; } 255 256 SmallFpImpl::NonRedValue sum; // initially sum = 0; 257 if (BlockSize > 0) 258 for (const FpElem* pause=fi+2*BlockSize; pause <= flast; pause += BlockSize) 259 { 260 for (; fi < pause; ++fi, --gj) 261 sum += (*fi) * (*gj); 262 sum = ModP.myHalfNormalize(sum); 263 } 264 for (; fi <= flast; ++fi, --gj) 265 sum += (*fi) * (*gj); 266 H[k] = ModP.myNormalize(sum); 267 } 268 } 269 270 DUPFp operator*(const DUPFp& f, const DUPFp& g) 271 { 272 DUPFp ans(0, f.myArith); 273 mul(ans, f, g); 274 return ans; 275 } 276 277 278 /***************************************************************************/ 279 /* This is an "in place" squaring function. */ 280 /* The multiplication routine above cannot do "in place" squaring, and */ 281 /* while this routine can easily be modified to do general multiplication */ 282 /* it is noticeably slower than the routine above. */ 283 284 square(const DUPFp & f)285 DUPFp square(const DUPFp& f) 286 { 287 CoCoA_THROW_ERROR(ERR::NYI, "square for DUPFp"); 288 return f*f; 289 // if (IsZero(f)) return DUPFp(0, f.myArith); 290 // const long df = deg(f); 291 // DUPFp ans(2*df, f.myArith); 292 // vector<FpElem>& G = ans.myCoeffs; 293 // G.resize(2*df); 294 295 // const long BlockSize = (dg<=2*MaxIters) ? 0 : MaxIters; 296 // for (long k=df-1; k >= 0; --k) 297 // { 298 // const FpElem *fi, *gj; 299 // const SmallFpImpl::value_* flast = &F[df]; 300 // const SmallFpImpl::value_* fi = &F[0]; 301 // if (2*k < df) flast = &F[2*k]; 302 // else fi = &F[2*k-df]; 303 304 // const FpElem* fj = flast; 305 306 // FpElem sum_even = 0; 307 // FpElem sum_odd = 0; 308 // if (BlockSize > 0) 309 // for (const FpElem* pause=fi+2*BlockSize; pause <= flast; pause += BlockSize) 310 // { 311 // for (; fi < pause; ++fi, --fj) 312 // { 313 // sum_even += *fi * *fj; 314 // sum_odd += *fi * *fj; 315 // } 316 // sum_even = ModP.myReduceQ(sum_even); 317 // sum_odd = ModP.myReduceQ(sum_odd); 318 // } 319 // for (; fi <= flast; ++fi, --fj) 320 // { 321 // sum_even += *fi * *gj; 322 // sum_odd += *fi * *fj; 323 // } 324 // H[k] = ModP.myReduce(sum); 325 // } 326 327 328 } 329 330 power_loop(DUPFp & ans,const DUPFp & base,long exp)331 void power_loop(DUPFp& ans, const DUPFp& base, long exp) 332 { 333 CoCoA_ASSERT(exp > 0); 334 if (exp == 1) { ans = base; return; } 335 power_loop(ans, base, exp/2); // integer division!! 336 square(ans); 337 if ((exp&1) == 0) return; 338 mul(ans,ans,base);//ans *= base; 339 } 340 power(const DUPFp & base,long exp)341 DUPFp power(const DUPFp& base, long exp) 342 { 343 if (exp < 0) CoCoA_THROW_ERROR(ERR::NegExp, "power(DUPFp,n)"); 344 if (exp == 0) { DUPFp ans(0, base.myArith); AssignOne(ans); return ans; } 345 if (IsZero(base)) 346 { 347 DUPFp ans(0, base.myArith); 348 AssignZero(ans); 349 return ans; 350 } 351 DUPFp ans(exp*deg(base), base.myArith); 352 power_loop(ans, base, exp); 353 return ans; 354 } 355 356 357 // f += c*x^exp*g ShiftAdd(DUPFp & f,const DUPFp & g,SmallFpImpl::value c,long DegShift)358 void ShiftAdd(DUPFp& f, const DUPFp& g, SmallFpImpl::value c, long DegShift) 359 { 360 typedef SmallFpImpl::value FpElem; 361 CoCoA_ASSERT(f.myArith == g.myArith); 362 if (IsZero(c)) return; 363 const SmallFpImpl& ModP = f.myArith; 364 const long df = deg(f); 365 const long dg = deg(g); 366 vector<FpElem>& F = f.myCoeffs; 367 const vector<FpElem>& G = g.myCoeffs; 368 if (dg+DegShift > df) F.resize(dg+DegShift+1); // fills with 0 369 370 // FpElem* Fj= &F[dg+exp]; 371 // const FpElem* const G0 = &G[0]; 372 // for (const FpElem* Gi = &G[dg]; Gi >= G0; --Gi, --Fj) 373 // ModP.myIsZeroAddMul(*Fj, c, *Gi); 374 ///// std::clog<<"ShiftAdd BEFORE LOOP DegShift="<<DegShift<<std::endl; 375 ///// std::clog<<"ShiftAdd f="<<f<<std::endl; 376 ///// std::clog<<"ShiftAdd g="<<g<<std::endl; 377 ///JJJ for (long i=dg; i >= 0; --i) 378 for (long i=0; i <= dg; ++i) 379 ModP.myIsZeroAddMul(F[i+DegShift], c, G[i]); // F[i+DegShift] = ModP.myNormalize(F[i+exp] + c*G[i]); 380 ///// std::clog<<"ShiftAdd f="<<f<<std::endl; 381 382 FixDeg(f); 383 } 384 385 // f += c*x^exp*g ShiftAdd(DUPFp & f,const DUPFp & g,const vector<SmallFpImpl::value> & MultTbl,long DegShift)386 void ShiftAdd(DUPFp& f, const DUPFp& g, const vector<SmallFpImpl::value>& MultTbl, long DegShift) 387 { 388 typedef SmallFpImpl::value FpElem; 389 CoCoA_ASSERT(f.myArith == g.myArith); 390 const SmallFpImpl& ModP = f.myArith; 391 const long df = deg(f); 392 const long dg = deg(g); 393 vector<FpElem>& F = f.myCoeffs; 394 const vector<FpElem>& G = g.myCoeffs; 395 if (dg+DegShift > df) F.resize(dg+DegShift+1); // fills with 0 396 397 // FpElem* Fj= &F[dg+exp]; 398 // const FpElem* const G0 = &G[0]; 399 // for (const FpElem* Gi = &G[dg]; Gi >= G0; --Gi, --Fj) 400 // ModP.myIsZeroAddMul(*Fj, c, *Gi); 401 ///// std::clog<<"ShiftAdd BEFORE LOOP DegShift="<<DegShift<<std::endl; 402 ///// std::clog<<"ShiftAdd f="<<f<<std::endl; 403 ///// std::clog<<"ShiftAdd g="<<g<<std::endl; 404 ///JJJ for (long i=dg; i >= 0; --i) 405 for (long i=0; i <= dg; ++i) 406 F[i+DegShift] = ModP.myAdd(F[i+DegShift], MultTbl[ModP.myExportNonNeg(G[i])]); 407 ///// std::clog<<"ShiftAdd f="<<f<<std::endl; 408 409 FixDeg(f); 410 } 411 412 413 DUPFp operator/(const DUPFp& num, const DUPFp& den) 414 { 415 CoCoA_ASSERT(num.myArith == den.myArith); 416 if (IsZero(den)) CoCoA_THROW_ERROR(ERR::DivByZero, "operator/ for DUPFp"); 417 if (IsZero(num)) return DUPFp(0, num.myArith);//??? return num;??? 418 const long dnum = deg(num); 419 const long dden = deg(den); 420 DUPFp quot(dnum-dden, num.myArith); 421 DUPFp rem(dden-1, num.myArith); 422 QuoRem(quot, rem, num, den); 423 return quot; 424 } 425 426 DUPFp operator%(const DUPFp& num, const DUPFp& den) 427 { 428 CoCoA_ASSERT(num.myArith == den.myArith); 429 if (IsZero(den)) CoCoA_THROW_ERROR(ERR::DivByZero, "operator/ for DUPFp"); 430 if (IsZero(num)) return DUPFp(0, num.myArith); 431 const long dnum = deg(num); 432 const long dden = deg(den); 433 DUPFp quot(dnum-dden, num.myArith); 434 DUPFp rem(dden-1, num.myArith); 435 QuoRem(quot, rem, num, den); 436 return rem; 437 } 438 439 QuoRem(DUPFp & q,DUPFp & r,const DUPFp & num,const DUPFp & den)440 void QuoRem(DUPFp& q, DUPFp& r, const DUPFp& num, const DUPFp& den) 441 { 442 if (&q == &r || &q == &num || &q == &den || 443 &r == &num || &r == &den) 444 CoCoA_THROW_ERROR(ERR::BadArg, "QuoRem args alias"); 445 const SmallFpImpl& ModP = num.myArith; 446 CoCoA_ASSERT(den.myArith == ModP); 447 CoCoA_ASSERT(q.myArith == ModP); 448 CoCoA_ASSERT(r.myArith == ModP); 449 if (IsZero(den)) CoCoA_THROW_ERROR(ERR::DivByZero, "QuoRem for DUPFp"); 450 if (IsZero(num)) { AssignZero(q); AssignZero(r); return; } 451 452 CoCoA_THROW_ERROR(ERR::NYI, "QuoRem"); 453 454 // CHECK FOR ALIASING!!! 455 // if (quot == rem || quot == den || rem == den) 456 // { 457 // JERROR(JERROR_DIV4_ARGS); 458 // return; 459 // } 460 const long dnum = deg(num); 461 const long dden = deg(den); 462 463 if (dnum < dden) /* quotient is zero, remainder = num */ 464 { 465 AssignZero(q); 466 r = num; 467 return; 468 } 469 470 typedef SmallFpImpl::value FpElem; 471 vector<FpElem>& Q = q.myCoeffs; 472 vector<FpElem>& R = r.myCoeffs; 473 ///??? const vector<FpElem>& N = num.myCoeffs; 474 const vector<FpElem>& D = den.myCoeffs; 475 476 vector<SmallFpImpl::NonRedValue> rem(dnum+1); 477 //???? replace loop below by std::copy or std::transform??? 478 for (long i=0; i <= dnum; ++i) 479 rem[i] = num.myCoeffs[i]; 480 481 long dquot = dnum-dden; 482 if (dquot > deg(q)) Q.resize(dquot+1); 483 r = num; 484 485 const FpElem lcdrecip = ModP.myRecip(D[dden]); 486 const long MaxIters = ModP.myMaxIters(); 487 long count = 0; 488 ///??? if (dden < k) k = dquot+1; /* disable "shifting" if den has low degree */ 489 490 for(long dtmp = dnum; dquot >= 0; --dquot, --dtmp) 491 { 492 const FpElem lc_rem = ModP.myNormalize(rem[dtmp]); 493 rem[dtmp] = lc_rem; 494 if (IsZero(lc_rem)) { Q[dquot] = zero(SmallFp); continue; } 495 Q[dquot] = ModP.myMul(lc_rem, lcdrecip); 496 const FpElem qq = ModP.myNegate(Q[dquot]); 497 for (long i=0; i < dden; ++i) 498 rem[i+dquot] += qq*D[i]; // NOT normalized!! 499 if (++count < MaxIters) continue; 500 count = 0; 501 for (long i=MaxIters; i < dden; ++i) 502 rem[i+dquot] = ModP.myHalfNormalize(rem[i+dquot]); 503 } 504 505 R.resize(dden); 506 for(long i=0; i < dden; ++i) R[i] = ModP.myNormalize(rem[i]); 507 FixDeg(r); // necessary? 508 } 509 510 deriv(const DUPFp & f)511 DUPFp deriv(const DUPFp& f) 512 { 513 long d = deg(f); 514 const SmallFpImpl& ModP = f.myArith; 515 const long p = ModP.myModulus(); 516 while (d > 0) 517 { 518 if (!IsZero(f.myCoeffs[d]) && (d%p != 0)) break; 519 --d; 520 } 521 if (d == 0) return DUPFp(0, ModP); 522 DUPFp fprime(d-1, ModP); 523 for (long i=1; i <= d; ++i) 524 fprime.myCoeffs[i-1] = ModP.myMul(ModP.myReduce(i), f.myCoeffs[i]); 525 return fprime; 526 } 527 528 529 // anon namespace? 530 // OVERWRITES ARGS!!! EuclidAlgm(DUPFp & f,DUPFp & g)531 DUPFp EuclidAlgm(DUPFp& f, DUPFp& g) 532 { 533 typedef SmallFpImpl::value FpElem; 534 CoCoA_ASSERT(f.myArith == g.myArith); 535 if (deg(f) < deg(g)) return EuclidAlgm(g, f); 536 537 const SmallFpImpl& ModP = f.myArith; 538 const long p = ModP.myModulus(); 539 while (!IsZero(g)) 540 { 541 while (deg(f) >= deg(g)) 542 { 543 const FpElem q = ModP.myNegate(ModP.myDiv(LC(f), LC(g))); 544 if (deg(g) < p) 545 ShiftAdd(f, g, q, deg(f)-deg(g)); 546 else 547 { 548 vector<FpElem> MultTbl(p); 549 FpElem x;for (int i=0; i < p; ++i) { MultTbl[i] = x; x = ModP.myAdd(x,q);} 550 ShiftAdd(f, g, MultTbl, deg(f)-deg(g)); 551 } 552 } 553 swap(f, g); 554 } 555 return f; 556 } 557 gcd(const DUPFp & f,const DUPFp & g)558 DUPFp gcd(const DUPFp& f, const DUPFp& g) 559 { 560 if (f.myArith != g.myArith) CoCoA_THROW_ERROR(ERR::MixedRings, "gcd for DUPFp"); 561 if (IsZero(f)) return monic(g); 562 if (IsZero(g)) return monic(f); 563 if (deg(f) == 0) return monic(f); 564 if (deg(g) == 0) return monic(g); 565 DUPFp fcopy = f; 566 DUPFp gcopy = g; 567 return monic(EuclidAlgm(fcopy, gcopy)); 568 } 569 ExtEuclidAlgm(DUPFp & cf,DUPFp & cg,DUPFp & f,DUPFp & g)570 DUPFp ExtEuclidAlgm(DUPFp& cf, DUPFp& cg, DUPFp& f, DUPFp& g) 571 { 572 typedef SmallFpImpl::value FpElem; 573 CoCoA_ASSERT(f.myArith == g.myArith); 574 if (deg(f) < deg(g)) return ExtEuclidAlgm(cg, cf, g, f); 575 576 const SmallFpImpl& ModP = f.myArith; 577 DUPFp m11(deg(g), ModP); AssignOne(m11); 578 DUPFp m12(deg(f), ModP); 579 DUPFp m21(deg(g), ModP); 580 DUPFp m22(deg(f), ModP); AssignOne(m22); 581 while (!IsZero(g)) 582 { 583 while (deg(f) >= deg(g)) 584 { 585 const FpElem q = ModP.myNegate(ModP.myDiv(LC(f), LC(g))); 586 const long DegShift = deg(f)-deg(g); 587 ///// std::clog<<"EEA: q="<<q<<" shift="<<DegShift<<std::endl; 588 ShiftAdd(f, g, q, DegShift); 589 ///// std::clog<<"BEFORE UPDATE:\n"; 590 ///// std::clog<<"m11="<<m11<<std::endl; 591 ///// std::clog<<"m12="<<m12<<std::endl; 592 ///// std::clog<<"m21="<<m21<<std::endl; 593 ///// std::clog<<"m22="<<m22<<std::endl; 594 ShiftAdd(m11, m21, q, DegShift); 595 ShiftAdd(m12, m22, q, DegShift); 596 ///// std::clog<<"AFTER UPDATE:\n"; 597 ///// std::clog<<"m11="<<m11<<std::endl; 598 ///// std::clog<<"m12="<<m12<<std::endl; 599 ///// std::clog<<"m21="<<m21<<std::endl; 600 ///// std::clog<<"m22="<<m22<<std::endl; 601 } 602 swap(f, g); 603 swap(m11, m21); 604 swap(m12, m22); 605 } 606 swap(cf, m11); // equiv. cf = m11; 607 swap(cg, m12); // equiv. cg = m12; 608 return f; 609 } 610 exgcd(DUPFp & cf,DUPFp & cg,const DUPFp & f,const DUPFp & g)611 DUPFp exgcd(DUPFp& cf, DUPFp& cg, const DUPFp& f, const DUPFp& g) 612 { 613 if (f.myArith != g.myArith) CoCoA_THROW_ERROR(ERR::MixedRings, "exgcd for DUPFp"); 614 if (cf.myArith != cg.myArith) CoCoA_THROW_ERROR(ERR::MixedRings, "exgcd for DUPFp"); 615 if (f.myArith != cf.myArith) CoCoA_THROW_ERROR(ERR::MixedRings, "exgcd for DUPFp"); 616 if (IsZero(f) && IsZero(g)) { AssignZero(cf); AssignZero(cg); return f; } // all zero! 617 if (IsZero(f) || deg(g) == 0) { AssignZero(cf); AssignOne(cg); cg /= LC(g); return monic(g); } 618 if (IsZero(g) || deg(f) == 0) { AssignOne(cf); AssignZero(cg); cf /= LC(f); return monic(f); } 619 620 DUPFp fcopy(f); // work on copies of f & g! 621 DUPFp gcopy(g); 622 DUPFp h = ExtEuclidAlgm(cf, cg, fcopy, gcopy); 623 cf /= LC(h); 624 cg /= LC(h); 625 return monic(h); 626 } 627 628 eval(const DUPFp & f,SmallFpImpl::value x)629 SmallFpImpl::value eval(const DUPFp& f, SmallFpImpl::value x) 630 { 631 typedef SmallFpImpl::value FpElem; 632 if (IsZero(f)) return zero(SmallFp); 633 if (deg(f) == 0) return LC(f); 634 const vector<FpElem>& F = f.myCoeffs; 635 if (IsZero(x)) return F[0]; 636 const SmallFpImpl& ModP = f.myArith; 637 FpElem ans; // ans = 0; 638 for (long i=deg(f); i >= 0; --i) 639 ans = ModP.myAddMul(F[i], ans, x); 640 /// ans = ModP.myAdd(F[i], ModP.myMul(ans, x)); 641 return ans; 642 } 643 644 645 bool operator==(const DUPFp& f, const DUPFp& g) 646 { 647 if (f.myArith != g.myArith) CoCoA_THROW_ERROR(ERR::MixedRings, "op== for DUPFp"); 648 if (deg(f) != deg(g)) return false; 649 return f.myCoeffs == g.myCoeffs; // let std::vector do the work :-) 650 } 651 652 bool operator!=(const DUPFp& f, const DUPFp& g) 653 { 654 return !(f == g); 655 } 656 657 658 std::ostream& operator<<(std::ostream& out, const DUPFp& f) 659 { 660 if (!out) return out; // short-cut for bad ostreams 661 if (IsZero(f)) { out << "0"; return out; } 662 const long d = deg(f); 663 const SmallFpImpl& ModP = f.myArith; 664 const long p = ModP.myModulus(); 665 out << "DUPFp(char=" << p << ", coeffs=[" << ModP.myExport(f.myCoeffs[d]); 666 for (long i=d-1; i >= 0; --i) 667 out << ", " << ModP.myExport(f.myCoeffs[i]); 668 out << "])"; 669 return out; 670 } 671 672 MulMod(const DUPFp & f,const DUPFp & g,const DUPFp & m)673 DUPFp MulMod(const DUPFp& f, const DUPFp& g, const DUPFp& m) 674 { 675 return (f*g)%m; 676 } 677 PowerMod(const DUPFp & f,long exp,const DUPFp & m)678 DUPFp PowerMod(const DUPFp& f, long exp, const DUPFp& m) 679 { 680 CoCoA_ASSERT(exp >= 0); 681 CoCoA_ASSERT(f.myArith == m.myArith); 682 CoCoA_ASSERT(deg(m) > 0); 683 CoCoA_ASSERT(deg(f) < deg(m)); 684 const SmallFpImpl& ModP = f.myArith; 685 DUPFp ans(deg(m), ModP); 686 if (exp == 0) { AssignOne(ans); return ans; } 687 if (exp == 1) return f; 688 ans = PowerMod(f, exp/2, m); 689 ans = MulMod(ans, ans, m); 690 if ((exp&1) == 0) return ans; 691 return MulMod(ans, f, m); 692 } 693 694 IsSqfr(const DUPFp & f)695 bool IsSqfr(const DUPFp& f) 696 { 697 if (IsZero(f)) return false; 698 if (deg(f) <= 1) return true; 699 return (deg(gcd(f, deriv(f))) == 0); 700 } 701 702 PthRoot(const DUPFp & f)703 DUPFp PthRoot(const DUPFp& f) 704 { 705 typedef SmallFpImpl::value FpElem; 706 if (IsZero(f) || deg(f) == 0) return f; 707 const SmallFpImpl& ModP = f.myArith; 708 const long p = ModP.myModulus(); 709 const long degf = deg(f); 710 CoCoA_ASSERT(degf%p == 0); 711 const vector<FpElem>& F = f.myCoeffs; 712 #ifdef CoCoA_DEBUG 713 for (long i=0; i <= degf; ++i) 714 CoCoA_ASSERT(i%p == 0 || IsZero(F[i])); 715 #endif 716 DUPFp ans(degf/p, ModP); 717 vector<FpElem>& A = ans.myCoeffs; 718 A.resize(1+degf/p); 719 for (long i=0; p*i <= degf; ++i) 720 A[i] = F[p*i]; 721 return ans; 722 } 723 724 SqfrDecomp(DUPFp f)725 factorization<DUPFp> SqfrDecomp(DUPFp f) 726 { 727 if (IsZero(f)) CoCoA_THROW_ERROR(ERR::NotNonZero, "SqfrDecomp"); 728 CoCoA_ASSERT(IsSqfr(f)); 729 vector<DUPFp> factors; 730 vector<long> multiplicities; 731 const SmallFpImpl& ModP = f.myArith; 732 const long p = ModP.myModulus(); 733 long q = 1; // q will always be a power of p. 734 735 while (deg(f) > 0) 736 { 737 DUPFp g = gcd(f, deriv(f)); 738 DUPFp radical = f/g; 739 swap(f, g); 740 long pwr = 0; 741 while (deg(radical) > 0) 742 { 743 ++pwr; 744 if (pwr%p == 0) { f = f/radical; continue; } 745 DUPFp NewRadical = gcd(f, radical); 746 if (deg(NewRadical) < deg(radical)) 747 { 748 factors.push_back(radical/NewRadical); 749 multiplicities.push_back(pwr*q); 750 swap(radical, NewRadical); 751 } 752 f = f/radical; 753 } 754 q *= p; 755 f = PthRoot(f); 756 } 757 DUPFp RemainingFactor(0, ModP); AssignOne(RemainingFactor); RemainingFactor *= LC(f); 758 return factorization<DUPFp>(factors, multiplicities, RemainingFactor); 759 } 760 DistinctDegFactor(DUPFp f)761 factorization<DUPFp> DistinctDegFactor(DUPFp f) 762 { 763 if (IsZero(f)) CoCoA_THROW_ERROR(ERR::NotNonZero, "DistinctDegFactor"); 764 CoCoA_ASSERT(IsSqfr(f)); 765 vector<DUPFp> factors; 766 const SmallFpImpl& ModP = f.myArith; 767 const long p = ModP.myModulus(); 768 DUPFp x(1, ModP); x.myCoeffs.resize(1); x.myCoeffs[1]=one(SmallFp); 769 DUPFp xpower(deg(f)-1, ModP); 770 xpower = x; 771 for (long d=1; d <= deg(f)/2; ++d) 772 { 773 xpower = PowerMod(xpower, p, f); 774 ///??? xpower -= x; 775 const DUPFp g = gcd(xpower-x, f); 776 ///??? xpower += x; 777 factors.push_back(g); 778 if (deg(g) == 0) continue; 779 f = f/g; 780 xpower = xpower%f; 781 } 782 if (deg(f) > 0) factors.push_back(monic(f)); 783 DUPFp RemainingFactor(0, ModP); AssignOne(RemainingFactor); RemainingFactor *= LC(f); 784 const vector<long> mult(len(factors), 1); 785 return factorization<DUPFp>(factors, mult, RemainingFactor); 786 } 787 788 ConvertToDUPFp(const SmallFpImpl & ModP,ConstRefRingElem f)789 DUPFp ConvertToDUPFp(const SmallFpImpl& ModP, ConstRefRingElem f) 790 { 791 if (!IsSparsePolyRing(owner(f))) CoCoA_THROW_ERROR(ERR::NotSparsePolyRing, "ConvertToDUPFp"); 792 CoCoA_ASSERT(UnivariateIndetIndex(f) >= 0); 793 //???? if (UnivariateIndetIndex(f) < 0) CoCoA_THROW_ERROR("not univariate","ConvertToDUPFp"); 794 const long degf = StdDeg(f); 795 DUPFp ans(degf, ModP); 796 ans.myCoeffs.resize(degf+1); 797 for (SparsePolyIter it = BeginIter(f); !IsEnded(it); ++it) 798 { 799 ans.myCoeffs[StdDeg(PP(it))] = ModP.myReduce(ConvertTo<BigInt>(coeff(it))); 800 } 801 return ans; 802 } 803 ConvertFromDUPFp(ConstRefRingElem x,const DUPFp & f)804 RingElem ConvertFromDUPFp(ConstRefRingElem x, const DUPFp& f) 805 { 806 if (!IsPolyRing(owner(x))) CoCoA_THROW_ERROR(ERR::NotPolyRing, "ConvertFromDUPFp"); 807 if (!IsIndet(x)) CoCoA_THROW_ERROR("x not indet", "ConvertFromDUPFp"); 808 const PolyRing P = owner(x); 809 const SmallFpImpl& ModP = f.myArith; 810 RingElem ans(P); 811 if (IsZero(f)) return ans; 812 const long degf = deg(f); 813 for (long i=0; i <= degf; ++i) 814 if (!IsZero(f.myCoeffs[i])) 815 ans += ModP.myExport(f.myCoeffs[i])*power(x,i); 816 return ans; 817 } 818 819 820 // ******* STOPGAP IMPL ********* factor(const DUPFp & f)821 factorization<DUPFp> factor(const DUPFp& f) 822 { 823 const SmallFpImpl& ModP = f.myArith; 824 const long p = ModP.myModulus(); 825 const long d = deg(f); 826 827 FF Fp = FFctor(p); 828 FFselect(Fp); 829 DUPFF F = DUPFFnew(d); 830 { FFelem* CoeffVec = F->coeffs; for (long i=0; i<=d; ++i) CoeffVec[i] = ModP.myExportNonNeg(f.myCoeffs[i]); } 831 F->deg = d; 832 DUPFFlist facs = DUPFFfactor(F); 833 DUPFFfree(F); 834 const long n = DUPFFlist_length(facs); 835 //std::clog<<"factor: n="<<n<<std::endl; 836 vector<DUPFp> irreds; irreds.reserve(n); 837 vector<long> multiplicity; multiplicity.reserve(n); 838 for (DUPFFlist curr=facs; curr != nullptr; curr = curr->next) 839 { 840 const long DegFac = DUPFFdeg(curr->poly); 841 DUPFp fac(DegFac, ModP); fac.myCoeffs.resize(DegFac+1); 842 for (long i=0; i <= DegFac; ++i) fac.myCoeffs[i] = ModP.myReduce(curr->poly->coeffs[i]); 843 //std::clog<<"factor: fac="<<fac<<std::endl; 844 irreds.push_back(monic(fac)); 845 multiplicity.push_back(curr->deg); 846 } 847 DUPFFlist_dtor(facs); 848 ///??? FFselect(0); 849 FFdtor(Fp); 850 DUPFp scalar(0, ModP); scalar.myCoeffs.resize(1); scalar.myCoeffs[0] = LC(f); 851 return factorization<DUPFp>(irreds, multiplicity, scalar); 852 } 853 854 } // end of namespace CoCoA 855