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