1 //   Copyright (c)  2005-2009,2015,2017  John Abbott, Anna M. Bigatti
2 
3 //   This file is part of the source of CoCoALib, the CoCoA Library.
4 
5 //   CoCoALib is free software: you can redistribute it and/or modify
6 //   it under the terms of the GNU General Public License as published by
7 //   the Free Software Foundation, either version 3 of the License, or
8 //   (at your option) any later version.
9 
10 //   CoCoALib is distributed in the hope that it will be useful,
11 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //   GNU General Public License for more details.
14 
15 //   You should have received a copy of the GNU General Public License
16 //   along with CoCoALib.  If not, see <http://www.gnu.org/licenses/>.
17 
18 
19 // Source code for class DistMPoly
20 
21 #include "CoCoA/DistrMPolyClean.H"
22 
23 #include "CoCoA/BigIntOps.H"
24 #include "CoCoA/BigRatOps.H"
25 
26 #include <algorithm>
27 //using std::swap; in ourSwap
28 #include <iostream>
29 //using << in output
30 //#include <vector> ---  included in DistrMPolyClean.H
31 using std::vector;
32 
33 
34 namespace CoCoA
35 {
36 
IsCompatible(const DistrMPolyClean & f,const DistrMPolyClean & g)37   bool IsCompatible(const DistrMPolyClean& f, const DistrMPolyClean& g)
38   {
39     return (f.myCoeffRing == g.myCoeffRing) &&
40            (f.myPPM == g.myPPM) &&
41            (&f.myMemMgr == &g.myMemMgr);
42   }
43 
44 
ourSwap(DistrMPolyClean & f,DistrMPolyClean & g)45   void DistrMPolyClean::ourSwap(DistrMPolyClean& f, DistrMPolyClean& g)
46   {
47     CoCoA_ASSERT(IsCompatible(f, g));
48     std::swap(f.mySummands, g.mySummands);
49     std::swap(f.myEnd, g.myEnd);
50     if (f.mySummands == nullptr) f.myEnd = &f.mySummands;  // CAREFUL if f or g is zero!
51     if (g.mySummands == nullptr) g.myEnd = &g.mySummands;  //
52   }
53 
54 
55   // MemPool DistrMPolyClean::summand::ourMemMgr(sizeof(DistrMPolyClean::summand),
56   //                                        "DistrMPolyClean::summand::ourMemMgr");
57 
58 
ourDeleteSummands(DistrMPolyClean::summand * ptr,MemPool & MemMgr)59   void DistrMPolyClean::ourDeleteSummands(DistrMPolyClean::summand* ptr/*,const ring& R, const PPMonoid& M*/, MemPool& MemMgr)
60   {
61     while (ptr != nullptr)
62     {
63       DistrMPolyClean::summand* next = ptr->myNext;
64       ptr->~summand();
65       MemMgr.free(ptr);
66       ptr = next;
67     }
68   }
69 
70 
DistrMPolyClean(const ring & R,const PPMonoid & PPM,MemPool & MemMgr)71   DistrMPolyClean::DistrMPolyClean(const ring& R, const PPMonoid& PPM, MemPool& MemMgr):
72       myCoeffRing(R),
73       myPPM(PPM),
74       myMemMgr(MemMgr)
75   {
76     mySummands = nullptr;
77     myEnd = &mySummands;
78   }
79 
80 
~DistrMPolyClean()81   DistrMPolyClean::~DistrMPolyClean()
82   {
83     ourDeleteSummands(mySummands/*, myCoeffRing, myPPM*/, myMemMgr);
84   }
85 
86 
DistrMPolyClean(const DistrMPolyClean & copy)87   DistrMPolyClean::DistrMPolyClean(const DistrMPolyClean& copy):
88       myCoeffRing(copy.myCoeffRing),
89       myPPM(copy.myPPM),
90       myMemMgr(copy.myMemMgr)
91   {
92     mySummands = nullptr;
93     myEnd = &mySummands;
94     // !!! THIS LOOP IS NOT EXCEPTION CLEAN !!!
95     for (summand* it = copy.mySummands; it != nullptr; it = it->myNext)
96       myPushBack(myCopySummand(it));
97   }
98 
99 
100   DistrMPolyClean& DistrMPolyClean::operator=(const DistrMPolyClean& rhs)
101   {
102     if (this == &rhs) return *this;
103     DistrMPolyClean copy(rhs);
104     ourSwap(*this, copy);
105     return *this;
106   }
107 
108 
109   DistrMPolyClean& DistrMPolyClean::operator=(const MachineInt& rhs)
110   {
111     myAssignZero();
112     if (IsZero(rhs)) return *this; // to avoid needless alloc/free
113     NewSummandPtr t(*this); t.myRenew();
114     myCoeffRing->myAssign(raw(t->myCoeff), rhs);
115     if (!IsZero(t->myCoeff))
116     {
117       mySummands = t.relinquish();
118       myEnd = &mySummands->myNext;
119     }
120     return *this;
121   }
122 
123 
124   DistrMPolyClean& DistrMPolyClean::operator=(const BigInt& rhs)
125   {
126     myAssignZero();
127     if (IsZero(rhs)) return *this; // to avoid needless alloc/free
128     NewSummandPtr t(*this); t.myRenew();
129     myCoeffRing->myAssign(raw(t->myCoeff), rhs);
130     if (!IsZero(t->myCoeff))
131     {
132       mySummands = t.relinquish();
133       myEnd = &mySummands->myNext;
134     }
135     return *this;
136   }
137 
138   DistrMPolyClean& DistrMPolyClean::operator=(const BigRat& rhs)
139   {
140     myAssignZero();
141     if (IsZero(rhs)) return *this; // to avoid needless alloc/free
142     NewSummandPtr t(*this); t.myRenew();
143     myCoeffRing->myAssign(raw(t->myCoeff), rhs);
144     if (!IsZero(t->myCoeff))
145     {
146       mySummands = t.relinquish();
147       myEnd = &mySummands->myNext;
148     }
149     return *this;
150   }
151 
152 
153 //----------------------------------------------------------------------
154 // operations on summands
155 
156 
myCopySummand(const summand * original)157   DistrMPolyClean::summand* DistrMPolyClean::myCopySummand(const summand* original) const
158   {
159     NewSummandPtr copy(*this);
160     copy.myRenew();
161 
162 //    copy->myCoeff = original->myCoeff;
163 //    copy->myPP = original->myPP;
164     myCoeffRing->myAssign(raw(copy->myCoeff), raw(original->myCoeff));
165     myPPM->myAssign(raw(copy->myPP), raw(original->myPP));
166     return copy.relinquish();
167   }
168 
169 
myAssignZero()170   void DistrMPolyClean::myAssignZero()
171   {
172     ourDeleteSummands(mySummands/*, myCoeffRing, myPPM*/, myMemMgr);
173     mySummands = nullptr;
174     myEnd = &mySummands;
175   }
176 
177 
myIsEqual(const summand * const lhs,const summand * const rhs)178   bool DistrMPolyClean::myIsEqual(const summand* const lhs, const summand* const rhs) const
179   {
180     return (myPPM->myIsEqual(raw(lhs->myPP), raw(rhs->myPP)) &&
181             myCoeffRing->myIsEqual(raw(lhs->myCoeff), raw(rhs->myCoeff)));
182   }
183 
184 
NumTerms(const DistrMPolyClean & f)185   long NumTerms(const DistrMPolyClean& f)
186   {
187     long nsummands = 0;
188     for (const DistrMPolyClean::summand* it = f.mySummands; it != nullptr; it = it->myNext)
189       ++nsummands;
190     return nsummands;
191   }
192 
193 
LC(const DistrMPolyClean & f)194   ConstRefRingElem LC(const DistrMPolyClean& f)
195   {
196     CoCoA_ASSERT(!IsZero(f));
197     return f.mySummands->myCoeff;
198   }
199 
200 
MoveLMToFront(DistrMPolyClean & f,DistrMPolyClean & g)201   void MoveLMToFront(DistrMPolyClean& f, DistrMPolyClean& g)
202   {
203     CoCoA_ASSERT(!IsZero(g));
204 
205     DistrMPolyClean::summand* ltg = g.mySummands;
206     g.mySummands = g.mySummands->myNext;
207     if (g.mySummands == nullptr) g.myEnd = &(g.mySummands);
208     ltg->myNext = nullptr;
209     f.myPushFront(ltg);
210   }
211 
212 
MoveLMToBack(DistrMPolyClean & f,DistrMPolyClean & g)213   void MoveLMToBack(DistrMPolyClean& f, DistrMPolyClean& g)
214   {
215     CoCoA_ASSERT(!IsZero(g));
216 
217     DistrMPolyClean::summand* ltg = g.mySummands;
218     g.mySummands = g.mySummands->myNext;
219     if (g.mySummands == nullptr) g.myEnd = &(g.mySummands);
220     ltg->myNext = nullptr;
221     f.myPushBack(ltg);
222   }
223 
224 
myDeleteLM()225   void DistrMPolyClean::myDeleteLM()
226   {
227     CoCoA_ASSERT(!IsZero(*this));
228 
229     DistrMPolyClean::summand* old_lm = mySummands;
230     mySummands = old_lm->myNext;
231     if (mySummands == nullptr) myEnd = &mySummands;
232     old_lm->myNext = nullptr;
233     ourDeleteSummands(old_lm/*, myCoeffRing, myPPM*/, myMemMgr);
234   }
235 
236 
237 //   void wdeg(degree& d, const DistrMPolyClean& f)
238 //   {
239 //     CoCoA_ASSERT(!IsZero(f));
240 //     f.myPPM->myWDeg(d, raw(f.mySummands->myPP));
241 //   }
242 
243 
244 //   int CmpWDeg(const DistrMPolyClean& f, const DistrMPolyClean& g)
245 //   {
246 //     CoCoA_ASSERT(!IsZero(f));
247 //     CoCoA_ASSERT(!IsZero(g));
248 //     if (!DistrMPolyClean::compatible(f, g))
249 //       CoCoA_THROW_ERROR("Incompatible polynomials", "CmpDeg(DistrMPolyClean,DistrMPolyClean)");
250 //     return f.myPPM->myCmpWDeg(raw(f.mySummands->myPP), raw(g.mySummands->myPP));
251 //   }
252 
253 
254 // This fn offers only the weak exception guarantee!!!
myAddMulSummand(const summand * s,const DistrMPolyClean & g,bool SkipLMg)255   void DistrMPolyClean::myAddMulSummand(const summand* s, const DistrMPolyClean& g, bool SkipLMg)  // this += s*g
256   {
257     CoCoA_ASSERT(IsCompatible(*this, g));
258     CoCoA_ASSERT(!IsZero(s->myCoeff));
259 
260     const ring& R = myCoeffRing;
261 
262     const summand* g_smnd = g.mySummands;
263     if (SkipLMg)    g_smnd = g_smnd->myNext;
264     summand** f_prev = &mySummands;
265     summand*  f_smnd = *f_prev;
266 
267     NewSummandPtr tmp_smnd(*this); tmp_smnd.myRenew();
268     RingElem tmp(myCoeffRing);
269 
270     int CMP = 0;
271 
272     //    bool qIsOne = IsOne(s->myPP);
273     bool qIsOne = false;
274 
275     for (; f_smnd != nullptr && g_smnd != nullptr; g_smnd = g_smnd->myNext)
276     {
277       R->myMul(raw(tmp_smnd->myCoeff), raw(s->myCoeff), raw(g_smnd->myCoeff));
278       if (R->myIsZero(raw(tmp_smnd->myCoeff)))
279         continue; // skip this g_smnd as coeff mults to 0
280       myPPM->myMul(raw(tmp_smnd->myPP), raw(s->myPP), raw(g_smnd->myPP));
281       if (qIsOne)
282       {
283         while (f_smnd != nullptr && (CMP=myPPM->myCmp(raw(f_smnd->myPP), raw(g_smnd->myPP))) >0)
284           f_smnd = *(f_prev = &f_smnd->myNext);
285         myPPM->myAssign(raw(tmp_smnd->myPP), raw(g_smnd->myPP));
286       }
287       else
288       {
289 //        myPPM->myMul(raw(tmp_smnd->myPP), raw(s->myPP), raw(g_smnd->myPP));
290         while (f_smnd != nullptr && (CMP=myPPM->myCmp(raw(f_smnd->myPP), raw(tmp_smnd->myPP))) >0)
291           f_smnd = *(f_prev = &f_smnd->myNext);
292       }
293       if (f_smnd == nullptr)
294       {
295 //        R->myMul(raw(tmp_smnd->myCoeff), raw(s->myCoeff), raw(g_smnd->myCoeff));
296         myPushBack(tmp_smnd.relinquish());
297         tmp_smnd.myRenew();
298         g_smnd = g_smnd->myNext;
299         break;
300       }
301       if (CMP == 0)
302       {
303 //        if (R->myIsZeroAddMul(raw(f_smnd->myCoeff), raw(tmp), raw(s->myCoeff), raw(g_smnd->myCoeff)))
304         R->myAdd(raw(f_smnd->myCoeff), raw(f_smnd->myCoeff), raw(tmp_smnd->myCoeff));
305         if (R->myIsZero(raw(f_smnd->myCoeff)))
306           myRemoveSummand(f_prev);  // f_prev = f_prev;
307         else
308           f_prev = &f_smnd->myNext;
309         f_smnd = *f_prev;
310       }
311       else // (CMP < 0)
312       {
313 //        R->myMul(raw(tmp_smnd->myCoeff), raw(s->myCoeff), raw(g_smnd->myCoeff));
314         myInsertSummand(tmp_smnd.relinquish(), f_prev);
315         tmp_smnd.myRenew();
316         f_prev = &(*f_prev)->myNext;
317       }
318     }
319     for (;g_smnd != nullptr; g_smnd = g_smnd->myNext)
320     {
321       R->myMul(raw(tmp_smnd->myCoeff), raw(s->myCoeff), raw(g_smnd->myCoeff));
322       if (R->myIsZero(raw(tmp_smnd->myCoeff))) continue;
323       myPPM->myMul(raw(tmp_smnd->myPP), raw(s->myPP), raw(g_smnd->myPP));
324       myPushBack(tmp_smnd.relinquish());
325       tmp_smnd.myRenew();
326     }
327 
328 //      clog << "AddMul: produced f=";output(clog,f);clog<<std::endl;
329 //      clog << "------------------------------------------------------"<<std::endl;
330 
331   }
332 
333 
myAddMulLM(const DistrMPolyClean & h,const DistrMPolyClean & g,bool SkipLMg)334   void DistrMPolyClean::myAddMulLM(const DistrMPolyClean& h, const DistrMPolyClean& g, bool SkipLMg)
335   {                                                 //???
336     if (IsZero(h)) CoCoA_THROW_ERROR(ERR::NotNonZero, "DistrMPolyClean::myAddMul");
337     myAddMulSummand(h.mySummands, g, SkipLMg);     //???
338   }                                                 //???
339 
340 
341 //   void DistrMPolyClean::myWeylAddMulSummand(const summand* s, const DistrMPolyClean& g, bool SkipLMg)
342 //   {
343 //     CoCoA_ASSERT(IsCompatible(*this, g));
344 
345 //     //    const PPOrdering& ord = ordering(myPPM);
346 //     const ring& R = myCoeffRing;
347 //     const size_t nvars = NumIndets(myPPM);
348 // //???    clog << "AddMul: Doing funny product of the following two polys" << std::endl;
349 // //???    output(clog, g);
350 // //???    CoCoA_ASSERT(myRefCount == 1);
351 //     //???    MakeWritable(f);
352 
353 //     const summand* g_term = g.mySummands;
354 //     if (SkipLMg)    g_term = g_term->myNext;
355 // //???    summand** f_prev = &mySummands;
356 // //???    summand*  f_term = *f_prev;
357 
358 //     DistrMPolyClean ppg = g;
359 //     vector<long> expv(nvars);
360 //     myPPM->myExponents(expv, raw(s->myPP));
361 // //???    clog << "expv: "; for (int i=0; i<myNumIndets;++i) clog << expv[i] << "  "; clog << std::endl;
362 //     for (size_t indet = nvars/2; indet < nvars; ++indet)
363 //     {
364 //       long n = expv[indet];
365 //       if (n == 0) continue;
366 // //???      clog << "AddMul: doing D variable with index " << indet - myNumIndets/2 << std::endl;
367 //       DistrMPolyClean der = ppg;
368 
369 // //???      ppg *= IndetPower(myPPM, indet, n);
370 //       ppg.myMulByPP(raw(IndetPower(myPPM, indet, n)));
371 // //      mul(raw(ppg), raw(ppg), raw(IndetPower(indet, n)));
372 
373 //       for (long i=1; i <= n; ++i)
374 //       {
375 //         deriv(der, der, indet-nvars/2);
376 // //???        deriv(raw(der), raw(der), indet-nvars/2);
377 // //???        clog << "der(" << i << ")="; output(clog, raw(der)); clog << std::endl;
378 
379 // //        ppg += binomial(n, i)*der*IndetPower(myPPM, indet, n-i); // *IndetPower(myPPM, h, 2*i); // for homog case
380 //         auto_ptr<summand> jaa(new summand(myCoeffRing, myPPM));
381 //         R->myAssign(raw(jaa->myCoeff), binomial(n, i));
382 //         myPPM->myMulIndetPower(raw(jaa->myPP), indet, n-i);
383 // // if (HOMOG_CASE)        myPPM->mul(jaa->myPP, jaa->myPP, IndetPower(myPPM, h, 2*i));
384 //         ppg.myAddMulSummand(jaa.get(), der, false);
385 //       }
386 //     }
387 //     { // f *= indet^deg(pp, indet); for the early vars
388 //       for (size_t indet = nvars/2; indet < nvars; ++indet)
389 //         expv[indet] = 0;
390 //       auto_ptr<summand> jaa(new summand(myCoeffRing, myPPM));
391 //       R->myAssign(raw(jaa->myCoeff), raw(s->myCoeff));
392 //       myPPM->myAssign(raw(jaa->myPP), expv);
393 //       myAddMulSummand(jaa.get(), ppg, false);
394 //     }
395 //   }
396 
397 
398 
399 
myReductionStep(const DistrMPolyClean & g)400   void DistrMPolyClean::myReductionStep(const DistrMPolyClean& g)
401   {
402     CoCoA_ASSERT(&g!=this);
403     CoCoA_ASSERT(mySummands != nullptr);
404     CoCoA_ASSERT(!IsZero(g));
405 
406     DistrMPolyClean tmp_poly(myCoeffRing, myPPM, myMemMgr);
407 
408     DivLM(tmp_poly, *this, g);
409     tmp_poly.myNegate();
410     myDeleteLM();
411     myAddMulLM(tmp_poly, g, /*SkipLMg = */ true );
412   }
413 
414 
ComputeFScaleAndGScale(ConstRefRingElem LCf,ConstRefRingElem LCg,RingElem & fscale,RingElem & gscale)415   static void ComputeFScaleAndGScale(ConstRefRingElem LCf,
416                                      ConstRefRingElem LCg,
417                                      RingElem& fscale,
418                                      RingElem& gscale)
419   {
420 //???    CoCoA_ASSERT(!R->myIsEqual(LCg,-1));
421     const RingElem gcdLC = gcd(LCf, LCg);
422     gscale = -LCf/gcdLC;
423     if (LCg == gcdLC)
424     {
425       fscale = 1;
426       return;
427     }
428     fscale = LCg/gcdLC;
429     if (!IsInvertible(fscale)) return;
430     gscale /= fscale;
431     fscale = 1;
432   }
433 
434 
myReductionStepGCD(const DistrMPolyClean & g,RingElem & fscale)435   void DistrMPolyClean::myReductionStepGCD(const DistrMPolyClean& g, RingElem& fscale)
436   {
437     CoCoA_ASSERT(&g!=this);
438     CoCoA_ASSERT(!IsZero(g));
439 
440     DistrMPolyClean tmp_poly(myCoeffRing, myPPM, myMemMgr);
441     RingElem gscale(myCoeffRing);
442 
443     ComputeFScaleAndGScale(LC(*this), LC(g), fscale, gscale);
444 
445     if ( !IsOne(fscale) )    myMulByCoeff(raw(fscale));
446     DivLM(tmp_poly, *this, g);
447     tmp_poly.myNegate();
448     myDeleteLM();
449     myAddMulLM(tmp_poly, g, /*SkipLMg = */ true);
450   }
451 
452 
myAddClear(DistrMPolyClean & g)453   void DistrMPolyClean::myAddClear(DistrMPolyClean& g) // sets g to 0 as a side-effect
454   {
455     const ring& R = myCoeffRing;
456     //    const PPOrdering& ord = ordering(myPPM);
457     typedef DistrMPolyClean::summand summand;
458 
459     summand*  g_smnd = g.mySummands;
460     summand** f_prev = &mySummands;
461     summand*  f_smnd = *f_prev;
462     int CMP=0;
463 //???    CoCoA_ASSERT(*(G.myEnd)==nullptr);//BUG HUNTING  ???
464 
465    //    clog << "input f = "; output(clog, *this) ;clog << std::endl;
466     while ( f_smnd!=nullptr && g_smnd!=nullptr )
467     {
468       while (f_smnd!=nullptr &&
469              (CMP = myPPM->myCmp(raw(f_smnd->myPP), raw(g_smnd->myPP))) >0)
470         f_smnd = *(f_prev = &f_smnd->myNext);
471       if (f_smnd == nullptr)  break;
472       //clog <<   "(myAddClear error: should never happen for Basic Reduction)" << std::endl;
473       g.mySummands = g.mySummands->myNext;
474       g_smnd->myNext = nullptr;
475       if (CMP == 0)
476       {
477         R->myAdd(raw(f_smnd->myCoeff), raw(f_smnd->myCoeff), raw(g_smnd->myCoeff));
478         if (IsZero(f_smnd->myCoeff))
479           myRemoveSummand(f_prev);
480         ourDeleteSummands(g_smnd/*, myCoeffRing, myPPM*/, myMemMgr);
481       }
482       else // (CMP < 0)
483       {
484         myInsertSummand(g_smnd, f_prev);
485         f_prev = &(*f_prev)->myNext;
486       }
487       f_smnd = *f_prev;
488       g_smnd = g.mySummands;
489     }
490     if (g.mySummands != nullptr)
491     {
492       *myEnd = g.mySummands;
493       myEnd = g.myEnd;
494       g.mySummands = nullptr;
495     }
496     g.myEnd = &g.mySummands;
497     //    if (rare) {clog << "f2 = "; output(clog, f) ;clog << std::endl;}
498   }
499 
500 
myAppendClear(DistrMPolyClean & g)501   void DistrMPolyClean::myAppendClear(DistrMPolyClean& g)  // sets g to 0; no throw guarantee!
502   {
503     if (g.mySummands == nullptr) return;
504     *(myEnd) = g.mySummands;
505     myEnd = g.myEnd;
506     g.mySummands = nullptr;
507     g.myEnd = &g.mySummands;
508   }
509 
510 
LPP(const DistrMPolyClean & f)511   ConstRefPPMonoidElem LPP(const DistrMPolyClean& f)
512   {
513     CoCoA_ASSERT(!IsZero(f));
514     return f.mySummands->myPP;
515   }
516 
517 
DivLM(DistrMPolyClean & lhs,const DistrMPolyClean & f,const DistrMPolyClean & g)518   void DivLM(DistrMPolyClean& lhs, const DistrMPolyClean& f, const DistrMPolyClean& g) // lhs = LM(f)/LM(g)
519   {
520     CoCoA_ASSERT(IsCompatible(f, g) && IsCompatible(lhs, f));
521     CoCoA_ASSERT(!IsZero(f) && !IsZero(g));
522     //    clog << "DivLM" << std::endl;
523     const ring& R = f.myCoeffRing;    // shorthand
524     typedef DistrMPolyClean::summand summand;            // shorthand
525     const summand* const LMf = f.mySummands;  // shorthand
526     const summand* const LMg = g.mySummands;  // shorthand
527 
528     DistrMPolyClean::NewSummandPtr SpareSummand(lhs); SpareSummand.myRenew();
529     CoCoA_ASSERT( R->myIsDivisible(raw(SpareSummand->myCoeff),
530                                    raw(LMf->myCoeff), raw(LMg->myCoeff)) );
531     R->myDiv(raw(SpareSummand->myCoeff), raw(LMf->myCoeff), raw(LMg->myCoeff));
532     (f.myPPM)->myDiv(raw(SpareSummand->myPP), raw(LMf->myPP), raw(LMg->myPP));
533     lhs.myAssignZero();  // CANNOT myAssignZero() EARLIER in case lhs aliases f or g.
534     lhs.myPushBack(SpareSummand.relinquish());
535   }
536 
537 
538 
539   // This is lengthier than you might expect because it is exception safe.
540   // It also works fine if c aliases a coefficient of the polynomial.
myMulByCoeff(RingElemConstRawPtr rawc)541   void DistrMPolyClean::myMulByCoeff(RingElemConstRawPtr rawc)
542   {
543     CoCoA_ASSERT(!myCoeffRing->myIsZero(rawc));
544     if (myCoeffRing->myIsOne(rawc)) return;
545     const long n = NumTerms(*this);
546     vector<RingElem> NewCoeffs(n, zero(myCoeffRing));
547     long k=0;
548     for (summand* it = mySummands; it != nullptr; it = it->myNext)
549     {
550       myCoeffRing->myMul(raw(NewCoeffs[k]), raw(it->myCoeff), rawc);
551       ++k;
552     }
553     // The new coeffs are in NewCoeffs now swap them into the poly,
554     // but if a coeff is 0 (!zero-divisors!), delete the corresponding term.
555     summand** SummandPtr = &mySummands;
556     summand* it = mySummands;
557     for (long k=0; k < n; ++k)
558     {
559       CoCoA_ASSERT(it != nullptr);
560       CoCoA_ASSERT(*SummandPtr == it);
561       if (!IsZero(NewCoeffs[k]))
562       {
563         myCoeffRing->mySwap(raw(NewCoeffs[k]), raw(it->myCoeff));
564         SummandPtr = &it->myNext;
565         it = it->myNext;
566         continue;
567       }
568       summand* next = it->myNext;
569       myRemoveSummand(SummandPtr);
570       it = next;
571     }
572   }
573 
574 
575   // This is lengthier than you might expect because it is exception safe.
576   // It also works fine if rawc aliases a coefficient of the polynomial.
myDivByCoeff(RingElemConstRawPtr rawc)577   bool DistrMPolyClean::myDivByCoeff(RingElemConstRawPtr rawc)
578   {
579     CoCoA_ASSERT(!myCoeffRing->myIsZero(rawc));
580     if (myCoeffRing->myIsOne(rawc)) return true;
581     vector<RingElem> NewCoeffs(NumTerms(*this), zero(myCoeffRing));
582     long n=0;
583     for (summand* it = mySummands; it != nullptr; it = it->myNext)
584     {
585       if (!myCoeffRing->myIsDivisible(raw(NewCoeffs[n]), raw(it->myCoeff), rawc))
586         return false;
587       ++n;
588     }
589     // The new coeffs are in NewCoeffs now swap them into the poly.
590     n = 0;
591     for (summand* it = mySummands; it != nullptr; it = it->myNext)
592     {
593       myCoeffRing->mySwap(raw(NewCoeffs[n]), raw(it->myCoeff));
594       ++n;
595     }
596     return true;
597   }
598 
599 
600   // This would not be exception safe if PP multiplication might allocate memory.
myMulByPP(PPMonoidElemConstRawPtr rawpp)601   void DistrMPolyClean::myMulByPP(PPMonoidElemConstRawPtr rawpp)
602   {
603     for (summand* f_smnd = mySummands; f_smnd != nullptr ; f_smnd = f_smnd->myNext)
604       myPPM->myMul(raw(f_smnd->myPP), raw(f_smnd->myPP), rawpp);
605   }
606 
607 // ??? WANT DIVISION BY A PP TOO???
608 
609 
610 //   void DistrMPolyClean::myWeylMul(PPMonoidElemConstRawPtr rawpp)
611 //   {
612 //     for (summand* f_smnd = mySummands; f_smnd != nullptr ; f_smnd = f_smnd->myNext)
613 //       myPPM->myMul(raw(f_smnd->myPP), raw(f_smnd->myPP), rawpp);
614 //   }
615 
616 
myPushFront(RingElemConstRawPtr rawc,const std::vector<long> & expv)617   void DistrMPolyClean::myPushFront(RingElemConstRawPtr rawc, const std::vector<long>& expv)
618   {
619     if (myCoeffRing->myIsZero(rawc)) return;
620 
621     NewSummandPtr tmp(*this); tmp.myRenew();
622     myCoeffRing->myAssign(raw(tmp->myCoeff), rawc);
623     myPPM->myAssign(raw(tmp->myPP), expv);
624     myPushFront(tmp.relinquish());
625   }
626 
627 
myPushBack(RingElemConstRawPtr rawc,const std::vector<long> & expv)628   void DistrMPolyClean::myPushBack(RingElemConstRawPtr rawc, const std::vector<long>& expv)
629   {
630     if (myCoeffRing->myIsZero(rawc)) return;
631 
632     NewSummandPtr tmp(*this); tmp.myRenew();
633     myCoeffRing->myAssign(raw(tmp->myCoeff), rawc);
634     myPPM->myAssign(raw(tmp->myPP), expv);
635     myPushBack(tmp.relinquish());
636   }
637 
638 
myPushFront(RingElemConstRawPtr rawc,PPMonoidElemConstRawPtr rawpp)639   void DistrMPolyClean::myPushFront(RingElemConstRawPtr rawc, PPMonoidElemConstRawPtr rawpp)
640   {
641     if (myCoeffRing->myIsZero(rawc)) return;
642 
643     NewSummandPtr tmp(*this); tmp.myRenew();
644     myCoeffRing->myAssign(raw(tmp->myCoeff), rawc);
645     myPPM->myAssign(raw(tmp->myPP), rawpp);
646     myPushFront(tmp.relinquish());
647   }
648 
649 
myPushBack(RingElemConstRawPtr rawc,PPMonoidElemConstRawPtr rawpp)650   void DistrMPolyClean::myPushBack(RingElemConstRawPtr rawc, PPMonoidElemConstRawPtr rawpp)
651   {
652     if (myCoeffRing->myIsZero(rawc)) return;
653 
654     NewSummandPtr tmp(*this); tmp.myRenew();
655     myCoeffRing->myAssign(raw(tmp->myCoeff), rawc);
656     myPPM->myAssign(raw(tmp->myPP), rawpp);
657     myPushBack(tmp.relinquish());
658   }
659 
660 
myPushFront(summand * t)661   void DistrMPolyClean::myPushFront(summand* t)
662   {
663     CoCoA_ASSERT(t->myNext == nullptr);
664     CoCoA_ASSERT(IsZero(*this) || myPPM->myCmp(raw(t->myPP), raw(mySummands->myPP)) > 0);
665     t->myNext = mySummands;
666     mySummands = t;
667     if (myEnd == &mySummands) myEnd = &t->myNext;
668   }
669 
670 
myPushBack(summand * t)671   void DistrMPolyClean::myPushBack(summand* t)
672   {
673     CoCoA_ASSERT(t->myNext == nullptr);
674     // Cannot easily check that t really is smaller than smallest PP in the polynomial.
675 #ifdef CoCoA__DEBUG
676     // Costly check that t really is smaller than smallest PP in the DistrMPolyInlFpPP.
677     if (!IsZero(*this))
678     {
679       summand* LastSummand = mySummands;
680       while (LastSummand->myNext != nullptr)
681         LastSummand = LastSummand->myNext;
682       CoCoA_ASSERT(cmp(t->myPP, LastSummand->myPP) < 0);
683       CoCoA_ASSERT(myPPM->myCmp(t->myPP, LastSummand->myPP) < 0);
684     }
685 #endif
686     *myEnd = t;
687     myEnd = &t->myNext;
688   }
689 
690 
myRemoveSummand(summand ** prev_link)691   void DistrMPolyClean::myRemoveSummand(summand** prev_link)
692   {
693     summand* DeleteMe = *prev_link;
694     CoCoA_ASSERT(DeleteMe != nullptr);
695     if (DeleteMe->myNext == nullptr)
696       myEnd = prev_link;
697 
698     *prev_link = DeleteMe->myNext;
699     DeleteMe->myNext = nullptr;
700     ourDeleteSummands(DeleteMe/*, myCoeffRing, myPPM*/, myMemMgr);
701   }
702 
703 
myInsertSummand(summand * s,summand ** prev_link)704   void DistrMPolyClean::myInsertSummand(summand* s, summand** prev_link)
705   {
706     s->myNext = (*prev_link);
707     (*prev_link) = s;
708     if (myEnd == prev_link) myEnd = &(s->myNext);
709   }
710 
711 
IsZeroAddLCs(DistrMPolyClean & f,DistrMPolyClean & g)712   bool IsZeroAddLCs(DistrMPolyClean& f, DistrMPolyClean& g)
713   {
714     CoCoA_ASSERT(IsCompatible(f, g));
715     CoCoA_ASSERT(!IsZero(f) && !IsZero(g));
716     CoCoA_ASSERT( LPP(f)==LPP(g) );
717     f.myCoeffRing->myAdd(raw(f.mySummands->myCoeff), raw(f.mySummands->myCoeff), raw(g.mySummands->myCoeff));
718     g.myDeleteLM();
719     if (!IsZero(f.mySummands->myCoeff)) return false;
720     f.myDeleteLM();
721     return true;
722   }
723 
724 
myNegate()725   void DistrMPolyClean::myNegate()
726   {
727     for (summand* iter = mySummands; iter != nullptr; iter = iter->myNext)
728       myCoeffRing->myNegate(raw(iter->myCoeff), raw(iter->myCoeff));   // MIGHT THROW???
729   }
730 
731 
add(DistrMPolyClean & lhs,const DistrMPolyClean & g,const DistrMPolyClean & h)732   void add(DistrMPolyClean& lhs, const DistrMPolyClean& g, const DistrMPolyClean& h)
733   {
734     CoCoA_ASSERT(IsCompatible(lhs, g) && IsCompatible(g, h));
735     const ring& R = lhs.myCoeffRing;
736     DistrMPolyClean ans(lhs.myCoeffRing, lhs.myPPM, lhs.myMemMgr);
737 
738     typedef DistrMPolyClean::summand summand;
739     const summand* gterm = g.mySummands;
740     const summand* hterm = h.mySummands;
741 
742     if (&lhs==&g && IsMonomial(h))
743     {
744       lhs.myAddMonomial(h);
745       return;
746     }
747     if (&lhs==&h && IsMonomial(g))
748     {
749       lhs.myAddMonomial(g);
750       return;
751     }
752 
753     DistrMPolyClean::NewSummandPtr SpareSummand(lhs); SpareSummand.myRenew();
754     while (gterm != nullptr && hterm != nullptr)
755     {
756       int cmp = (lhs.myPPM)->myCmp(raw(gterm->myPP), raw(hterm->myPP));
757 
758       if (cmp < 0)
759       {
760 	summand* hcopy = ans.myCopySummand(hterm);
761 	ans.myPushBack(hcopy);
762 	hterm = hterm->myNext;
763 	continue;
764       }
765 
766       if (cmp > 0)
767       {
768 	summand* gcopy = ans.myCopySummand(gterm);
769 	ans.myPushBack(gcopy);
770 	gterm = gterm->myNext;
771 	continue;
772       }
773 
774       // Must have cmp == 0 here.
775       // The leading PPs are the same, so we sum the coeffs.
776       R->myAdd(raw(SpareSummand->myCoeff), raw(gterm->myCoeff), raw(hterm->myCoeff));
777       if (!IsZero(SpareSummand->myCoeff))
778       {
779 	(lhs.myPPM)->myAssign(raw(SpareSummand->myPP), raw(gterm->myPP)); // set PP ordv
780 	ans.myPushBack(SpareSummand.relinquish());
781         SpareSummand.myRenew();
782       }
783       gterm = gterm->myNext;
784       hterm = hterm->myNext;
785     }
786     while (gterm != nullptr)
787     {
788       summand* gcopy = ans.myCopySummand(gterm);
789       ans.myPushBack(gcopy);
790       gterm = gterm->myNext;
791     }
792     while (hterm != nullptr)
793     {
794       summand* hcopy = ans.myCopySummand(hterm);
795       ans.myPushBack(hcopy);
796       hterm = hterm->myNext;
797     }
798 
799     swap(lhs, ans); // really an assignment
800   }
801 
802 
803   // EXEPTION SAFE
myAddMonomial(const DistrMPolyClean & g)804   void DistrMPolyClean::myAddMonomial(const DistrMPolyClean& g)
805   {
806     CoCoA_ASSERT(IsCompatible(*this, g));
807     CoCoA_ASSERT(NumTerms(g)==1);
808 
809     typedef DistrMPolyClean::summand summand;
810     summand** f_prev = &mySummands;
811     summand*  f_smnd = *f_prev;
812     NewSummandPtr s(*this); s.myRenew();
813     s->myCoeff = g.mySummands->myCoeff; s->myPP = g.mySummands->myPP;
814 
815     int CMP;
816     while (f_smnd!=nullptr &&
817            (CMP = myPPM->myCmp(raw(f_smnd->myPP), raw(s->myPP))) >0)
818       f_smnd = *(f_prev = &f_smnd->myNext);
819     if (f_smnd == nullptr)  { myPushBack(s.relinquish()); return; }
820 
821     if (CMP < 0)
822     {
823       myInsertSummand(s.relinquish(), f_prev);
824       f_prev = &(*f_prev)->myNext;
825       return;
826     }
827 
828     myCoeffRing->myAdd(raw(s->myCoeff), raw(f_smnd->myCoeff), raw(s->myCoeff));
829     if (IsZero(s->myCoeff))
830       myRemoveSummand(f_prev);
831     else
832       myCoeffRing->mySwap(raw(s->myCoeff), raw(f_smnd->myCoeff));
833   }
834 
835 
sub(DistrMPolyClean & lhs,const DistrMPolyClean & g,const DistrMPolyClean & h)836   void sub(DistrMPolyClean& lhs, const DistrMPolyClean& g, const DistrMPolyClean& h)
837   {
838     // This code is almost a copy of add(...).
839     CoCoA_ASSERT(IsCompatible(lhs, g) && IsCompatible(g, h));
840     const ring& R = lhs.myCoeffRing;
841     DistrMPolyClean ans(lhs.myCoeffRing, lhs.myPPM, lhs.myMemMgr);
842 
843     typedef DistrMPolyClean::summand summand;
844     const summand* gterm = g.mySummands;
845     const summand* hterm = h.mySummands;
846     DistrMPolyClean::NewSummandPtr SpareSummand(lhs); SpareSummand.myRenew();
847     while (gterm != nullptr && hterm != nullptr)
848     {
849       int ord = (lhs.myPPM)->myCmp(raw(gterm->myPP), raw(hterm->myPP));
850 
851       if (ord < 0)
852       {
853 	summand* hcopy = ans.myCopySummand(hterm);
854 	R->myNegate(raw(hcopy->myCoeff), raw(hcopy->myCoeff));  //??? can this throw?
855 	ans.myPushBack(hcopy);
856 	hterm = hterm->myNext;
857 	continue;
858       }
859 
860       if (ord > 0)
861       {
862 	summand* gcopy = ans.myCopySummand(gterm);
863 	ans.myPushBack(gcopy);
864 	gterm = gterm->myNext;
865 	continue;
866       }
867 
868       // The leading PPs are the same, so we subtract the coeffs.
869       R->mySub(raw(SpareSummand->myCoeff), raw(gterm->myCoeff), raw(hterm->myCoeff));
870       if (!IsZero(SpareSummand->myCoeff))
871       {
872 	(lhs.myPPM)->myAssign(raw(SpareSummand->myPP), raw(gterm->myPP)); // set PP ordv
873 	ans.myPushBack(SpareSummand.relinquish());
874         SpareSummand.myRenew();
875       }
876       gterm = gterm->myNext;
877       hterm = hterm->myNext;
878     }
879     while (gterm != nullptr)
880     {
881       summand* gcopy = ans.myCopySummand(gterm);
882       ans.myPushBack(gcopy);
883       gterm = gterm->myNext;
884     }
885     while (hterm != nullptr)
886     {
887       summand* hcopy = ans.myCopySummand(hterm);
888       R->myNegate(raw(hcopy->myCoeff), raw(hcopy->myCoeff));  //??? can this throw?
889       ans.myPushBack(hcopy);
890       hterm = hterm->myNext;
891     }
892 
893     swap(lhs, ans); // really an assignment
894   }
895 
896 
897 //   bool div(DistrMPolyClean& lhs, const DistrMPolyClean& g, const DistrMPolyClean& h)  // result is true iff quotient is exact.
898 //   {
899 //     if (IsZero(h)) return false; //???CoCoA_THROW_ERROR(ERR::DivByZero,"div(DMP,DMP,DMP)");
900 //     PPMonoid PPM = lhs.myPPM;
901 //     //    const PPOrdering ord = ordering(PPM);
902 //     const ring& R = lhs.myCoeffRing;
903 //     const DistrMPolyClean::summand* LMh = h.mySummands;
904 //     const PPMonoidElem LPPden(LMh->myPP);
905 //     DistrMPolyClean ans(lhs.myCoeffRing, lhs.myPPM, lhs.myMemMgr);
906 //     DistrMPolyClean dividend(g);
907 //     while (!IsZero(dividend))
908 //     {
909 //       const DistrMPolyClean::summand* LMdividend = dividend.mySummands;
910 //       auto_ptr<DistrMPolyClean::summand> qterm(new DistrMPolyClean::summand(R, lhs.myPPM));
911 //       if (!R->myIsDivisible(raw(qterm->myCoeff), raw(LMdividend->myCoeff), raw(LMh->myCoeff))) return false;
912 //       {
913 //         PPMonoidElem LPPnum(LMdividend->myPP);
914 //         if (!IsDivisible(LPPnum, LPPden)) return false;
915 //       }
916 //       PPM->myDiv(raw(qterm->myPP), raw(LMdividend->myPP), raw(LMh->myPP));  //??? check whether this fails!
917 //       R->myNegate(raw(qterm->myCoeff), raw(qterm->myCoeff));
918 //       dividend.myAddMulSummand(qterm.get(), h, false);
919 //       R->myNegate(raw(qterm->myCoeff), raw(qterm->myCoeff));
920 //       ans.myPushBack(qterm.release());
921 //     }
922 //     swap(lhs, ans); // really an assignment
923 //     return true;
924 //   }
925 
926 
output(std::ostream & out,const DistrMPolyClean & f)927   void output(std::ostream& out, const DistrMPolyClean& f)  // for debugging only
928   {
929     if (!out) return;  // short-cut for bad ostreams
930     if (IsZero(f)) { out << "0"; return; }
931     for (DistrMPolyClean::summand* it = f.mySummands; it != nullptr; it = it->myNext)
932       out << " +(" << it->myCoeff << ")*" << it->myPP;
933   }
934 
935 
936 //   bool IsConstant(const DistrMPolyClean& f)
937 //   {
938 //     if (IsZero(f)) return true;
939 //     if (!IsMonomial(f)) return false;
940 //     return IsOne(LPP(f));
941 //   }
942 
943 
IsZero(const DistrMPolyClean & f)944   bool IsZero(const DistrMPolyClean& f)
945   {
946     return (f.mySummands == nullptr);
947   }
948 
949 
950 //   bool IsOne(const DistrMPolyClean& f)
951 //   {
952 //     if (IsZero(f) || f.mySummands->myNext != nullptr) return false;
953 //     if (!IsOne(f.mySummands->myPP)) return false;
954 //     return IsOne(f.mySummands->myCoeff);
955 //   }
956 
957 
958 //   bool IsMinusOne(const DistrMPolyClean& f)
959 //   {
960 //     if (IsZero(f) || f.mySummands->myNext != nullptr) return false;
961 //     if (!IsOne(f.mySummands->myPP)) return false;
962 //     return IsMinusOne(f.mySummands->myCoeff);
963 //   }
964 
965 
966 //   bool IsConstant(const DistrMPolyClean& f)
967 //   {
968 //     if (IsZero(f)) return true;
969 //     if (f.mySummands->myNext != nullptr) return false; // NULL ptr
970 //     return IsOne(f.mySummands->myPP);
971 //   }
972 
973 
974 //   bool IsIndet(std::size_t& IndetIndex, const DistrMPolyClean& f)
975 //   {
976 //     if (IsZero(f)) return false;
977 //     if (f.mySummands->myNext != nullptr) return false; // NULL ptr
978 //     if (!IsOne(f.mySummands->myCoeff)) return false;
979 //     return IsIndet(IndetIndex, f.mySummands->myPP);
980 //   }
981 
982 
IsMonomial(const DistrMPolyClean & f)983   bool IsMonomial(const DistrMPolyClean& f)
984   {
985     if (IsZero(f) || f.mySummands->myNext != nullptr) return false;
986     return true;
987   }
988 
989 
IsEqual(const DistrMPolyClean & f,const DistrMPolyClean & g)990   bool IsEqual(const DistrMPolyClean& f, const DistrMPolyClean& g)
991   {
992     CoCoA_ASSERT(IsCompatible(f, g));
993     if (&f == &g) return true;
994     const DistrMPolyClean::summand* fterm = f.mySummands;
995     const DistrMPolyClean::summand* gterm = g.mySummands;
996     while (fterm != nullptr && gterm != nullptr)
997     {
998       if (!f.myIsEqual(fterm, gterm)) return false;
999       fterm = fterm->myNext;
1000       gterm = gterm->myNext;
1001     }
1002     return fterm == gterm; // either both are nullptr (when the polys are equal), or only one is nullptr
1003   }
1004 
1005 
1006 //   void WeylMul(DistrMPolyClean& lhs, const DistrMPolyClean& g, const DistrMPolyClean& h)
1007 //   {
1008 
1009 //   }
1010 
1011 
1012 //   void WeylDiv(DistrMPolyClean& lhs, const DistrMPolyClean& g, const DistrMPolyClean& h)
1013 //   {
1014 //     CoCoA_THROW_ERROR(ERR::NYI, "WeylDiv (DistrMPolyClean)");
1015 //   }
1016 
1017 
1018 //   void deriv(DistrMPolyClean& lhs, const DistrMPolyClean& f, std::size_t IndetIndex)
1019 //   {
1020 //     deriv(lhs, f, indet(f.myPPM, IndetIndex));
1021 //   }
1022 
1023 
1024 //   void deriv(DistrMPolyClean& lhs, const DistrMPolyClean& f, ConstRefPPMonoidElem x)
1025 //   {
1026 //     if (IsOne(x)) { lhs = f; return; }
1027 //     const size_t nvars = NumIndets(owner(x));
1028 //     //    const PPOrdering ord = ordering(owner(x));
1029 //     const PPMonoid PPM = owner(x);
1030 //     const ring& R = f.myCoeffRing;
1031 //     vector<long> expv(nvars);
1032 //     exponents(expv, x);
1033 //     //    vector<PPOrderingBase::OrdvElem> ordvx(OrdvWords(ord));
1034 //     //    PPM->myInit(&ordvx[0], &expv[0]);
1035 // //clog<<"differentiating wrt expv: [";for(size_t i=0;i<nvars;++i)clog<<expv[i]<<" ";clog<<"]"<<std::endl;
1036 //     DistrMPolyClean ans(f.myCoeffRing, f.myPPM, f.myMemMgr);
1037 
1038 //     for (const DistrMPolyClean::summand* f_term = f.mySummands; f_term != nullptr; f_term = f_term->myNext)
1039 //     {
1040 // //clog<<"LOOPHEAD\n";
1041 //       BigInt scale(1);
1042 //       for (size_t indet=0; indet < nvars; ++indet)
1043 //       {
1044 //         if (expv[indet] == 0) continue;
1045 //         long d = PPM->myExponent(raw(f_term->myPP), indet);
1046 // //clog<<"log is "<<d<<" wrt var "<<indet<<std::endl;
1047 //         if (d < expv[indet]) { scale = 0; break; }
1048 //         scale *= RangeFactorial(d-expv[indet]+1, d);
1049 //       }
1050 // //if(IsZero(scale))clog<<"skipping term\n";
1051 //       if (IsZero(scale)) continue;
1052 // //clog<<"rescaling term by "<<scale<<std::endl;
1053 //       auto_ptr<DistrMPolyClean::summand> tmp(new DistrMPolyClean::summand(R, PPM));
1054 //       R->myAssign(raw(tmp->myCoeff), scale);
1055 //       R->myMul(raw(tmp->myCoeff), raw(tmp->myCoeff), raw(f_term->myCoeff));
1056 //       if (IsZero(tmp->myCoeff)) continue;
1057 // //clog<<"dividing ordv [";for(size_t i=0;i<2;++i)clog<<f_term->myPP[i]<<" ";clog<<"]\n";
1058 // //clog<<"by       ordv [";for(size_t i=0;i<2;++i)clog<<ordvx[i]<<" ";clog<<"]\n";
1059 //       PPM->myDiv(raw(tmp->myPP), raw(f_term->myPP), raw(x));
1060 // //clog<<"Quotient is   [";for(size_t i=0;i<2;++i)clog<<tmp->myPP[i]<<" ";clog<<"]\n";
1061 //       ans.myPushBack(tmp.release());
1062 //     }
1063 //     swap(lhs, ans); // really an assignment
1064 //   }
1065 
1066 
1067 
1068 //  //----------------------------------------------------------------------
1069 
1070 //    PolyIter::PolyIter(const PolyRing& Rx, DistrMPolyClean::summand** ptrptr):
1071 //      myPolyRing(Rx),
1072 //      myPtrPtr(ptrptr),
1073 //      myExpv(NumIndets(Rx))
1074 //    {}
1075 
1076 
1077 //    PolyIter::PolyIter(const PolyIter& copy):
1078 //      myPolyRing(copy.myPolyRing),
1079 //      myPtrPtr(copy.myPtrPtr),
1080 //      myExpv(NumIndets(myPolyRing))
1081 //    {}
1082 
1083 
1084 //    PolyIter& PolyIter::operator=(const PolyIter& rhs)
1085 //    {
1086 //      CoCoA_ASSERT(&myPolyRing == &rhs.myPolyRing);
1087 //      myPtrPtr = rhs.myPtrPtr;
1088 //      return *this;
1089 //    }
1090 
1091 
1092 //    PolyIter& PolyIter::operator++()
1093 //    {
1094 //      CoCoA_ASSERT(*myPtrPtr != nullptr);
1095 //      myPtrPtr = &((*myPtrPtr)->myNext);
1096 //      return *this;
1097 //    }
1098 
1099 
1100 //    PolyIter PolyIter::operator++(int)
1101 //    {
1102 //      CoCoA_ASSERT(*myPtrPtr != nullptr);
1103 //      PolyIter copy(*this);
1104 //      myPtrPtr = &((*myPtrPtr)->myNext);
1105 //      return copy;
1106 //    }
1107 
1108 
1109 //    bool operator==(const PolyIter& lhs, const PolyIter& rhs)
1110 //    {
1111 //      return lhs.myPtrPtr == rhs.myPtrPtr;
1112 //    }
1113 
1114 
1115 //    bool operator!=(const PolyIter& lhs, const PolyIter& rhs)
1116 //    {
1117 //      return lhs.myPtrPtr != rhs.myPtrPtr;
1118 //    }
1119 
1120 
1121 //    RingElemRawPtr RawCoeff(PolyIter& i)
1122 //    {
1123 //      CoCoA_ASSERT(*i.myPtrPtr != nullptr);
1124 //      return (*i.myPtrPtr)->myCoeff;
1125 //    }
1126 
1127 
1128 //    const RingElem coeff(const PolyIter& i)
1129 //    {
1130 //      CoCoA_ASSERT(*i.myPtrPtr != nullptr);
1131 //      return RingElem(CoeffRing(i.myPolyRing), (*i.myPtrPtr)->myCoeff);
1132 //    }
1133 
1134 
1135 //    PPMonoidElem pp(PolyIter& i)
1136 //    {
1137 //      CoCoA_ASSERT(*i.myPtrPtr != nullptr);
1138 //      return PPMonoidElem(PPM(i.myPolyRing), PPMonoidElem::FromOrdv, (*i.myPtrPtr)->myPP);
1139 //    }
1140 
1141 
1142 //    PPOrdering::OrdvElem* ordv(PolyIter& i)
1143 //    {
1144 //      CoCoA_ASSERT(*i.myPtrPtr != nullptr);
1145 //      return (*i.myPtrPtr)->myPP;
1146 //    }
1147 
1148 
1149 
1150 } // end of namespace CoCoA
1151 
1152 
1153 
1154 // RCS header/log in the next few lines
1155 // $Header: /Volumes/Home_1/cocoa/cvs-repository/CoCoALib-0.99/src/AlgebraicCore/DistrMPolyClean.C,v 1.30 2020/06/17 15:49:22 abbott Exp $
1156 // $Log: DistrMPolyClean.C,v $
1157 // Revision 1.30  2020/06/17 15:49:22  abbott
1158 // Summary: Changed CoCoA_ERROR into CoCoA_THROW_ERROR
1159 //
1160 // Revision 1.29  2020/02/11 16:56:40  abbott
1161 // Summary: Corrected last update (see redmine 969)
1162 //
1163 // Revision 1.28  2020/02/11 16:12:17  abbott
1164 // Summary: Added some checks for bad ostream (even to mem fns myOutput); see redmine 969
1165 //
1166 // Revision 1.27  2019/10/15 11:54:08  abbott
1167 // Summary: Changed 0 into nullptr (where appropriate)
1168 //
1169 // Revision 1.26  2019/03/19 11:07:07  abbott
1170 // Summary: Replaced 0 by nullptr where appropriate
1171 //
1172 // Revision 1.25  2018/05/22 14:16:39  abbott
1173 // Summary: Split BigRat into BigRat (class defn + ctors) and BigRatOps
1174 //
1175 // Revision 1.24  2018/05/18 12:13:36  bigatti
1176 // -- renamed IntOperations --> BigIntOps
1177 //
1178 // Revision 1.23  2017/12/18 12:07:26  abbott
1179 // Summary: Correct handling for polys with coeffs in rings with zero-divisors
1180 //
1181 // Revision 1.22  2015/11/24 17:46:56  abbott
1182 // Summary: Corrected MoveLMToFront
1183 //
1184 // Revision 1.21  2015/11/04 10:42:05  abbott
1185 // Summary: Replaced auto_ptr<summand>  with  NewSummandPtr
1186 //
1187 // Revision 1.20  2015/04/27 10:30:51  bigatti
1188 // -- commented out excessive assert in myPushFront
1189 //
1190 // Revision 1.19  2015/04/27 10:06:04  bigatti
1191 // -- simplified myAppendClear
1192 // -- fixed myMoveLMToBack
1193 // -- added CoCoA_ASSERT to myMoveLMToBack and myMoveLMToFront
1194 //
1195 // Revision 1.18  2015/04/24 15:40:58  bigatti
1196 // -- renamed: myAddMul --> myAddMulLM
1197 // -- renamed: myMoveLM --> myMoveLMToFront
1198 // -- new myMoveLMToBack (used in ReductionCog --> bug in test-TmpMorseGraph??)
1199 //
1200 // Revision 1.17  2015/04/17 16:24:07  abbott
1201 // Summary: Added check that first arg is non-zero
1202 // Author: JAA
1203 //
1204 // Revision 1.16  2014/04/30 16:05:21  abbott
1205 // Summary: Replaced size_t by long
1206 // Author: JAA
1207 //
1208 // Revision 1.15  2014/01/28 10:57:24  bigatti
1209 // -- removed useless ==1 on boolean
1210 //
1211 // Revision 1.14  2012/10/24 12:13:34  abbott
1212 // Added keyword const to local variable in ComputeFScaleAndGScale.
1213 //
1214 // Revision 1.13  2012/10/16 10:27:34  abbott
1215 // Replaced  RefRingElem  by  RingElem&
1216 //
1217 // Revision 1.12  2012/10/11 14:27:59  abbott
1218 // Removed "semantically risky" function RefLC/RawLC from DistrMPoly*.
1219 // Reimplemented myRecvTwinFloat in RingDistrMPoly* more cleanly (but
1220 // new impl does make a wasteful copy of the coeff).
1221 //
1222 // Revision 1.11  2012/10/05 15:33:28  bigatti
1223 // -- added myAddMonomial
1224 //
1225 // Revision 1.10  2012/05/28 09:18:21  abbott
1226 // Created IntOperations which gathers together all operations on
1227 // integers (both big and small).  Many consequential changes.
1228 //
1229 // Revision 1.9  2012/01/25 13:43:45  bigatti
1230 // -- moved up: IsCompatible, ourSwap
1231 //
1232 // Revision 1.8  2011/11/09 14:03:59  bigatti
1233 // -- renamed MachineInteger --> MachineInt
1234 //
1235 // Revision 1.7  2011/08/24 10:25:53  bigatti
1236 // -- renamed QQ --> BigRat
1237 // -- sorted #include
1238 //
1239 // Revision 1.6  2011/08/14 15:52:17  abbott
1240 // Changed ZZ into BigInt (phase 1: just the library sources).
1241 //
1242 // Revision 1.5  2011/07/15 16:54:04  abbott
1243 // Minor correction to a comment.
1244 //
1245 // Revision 1.4  2011/06/23 16:04:47  abbott
1246 // Added IamExact mem fn for rings.
1247 // Added myRecvTwinFloat mem fn for rings.
1248 // Added first imple of RingHom from RingTwinFloat to other rings.
1249 //
1250 // Revision 1.3  2010/12/26 13:04:37  abbott
1251 // Changed "GlobalXXXput" into corresponding std C++ stream
1252 // (even in commented out code).
1253 //
1254 // Revision 1.2  2010/12/20 15:19:29  bigatti
1255 // -- modified IsZeroAddMul with temporary variable (slug found with cyclotomic)
1256 //
1257 // Revision 1.1  2010/10/08 08:05:28  bigatti
1258 // -- renamed (Ring)DistrMPoly --> (Ring)DistrMPolyClean
1259 //
1260 // Revision 1.12  2009/12/03 17:40:36  abbott
1261 // Added include directives for ZZ.H (as a consequence of removing
1262 // the directive from ring.H).
1263 //
1264 // Revision 1.11  2009/10/02 13:47:07  bigatti
1265 // -- myDivByCoeff now returns bool
1266 // -- unique implementation of myDiv in PolyRing.C
1267 //
1268 // Revision 1.10  2009/09/28 17:14:41  bigatti
1269 // -- commented out unused functions (div, deriv, *Weyl*)
1270 //
1271 // Revision 1.9  2008/12/17 12:11:52  abbott
1272 // Changed type from long to MachineInt in operations which use a machine integer
1273 // in place of a RingElem.  The change is "superficial" but affects many files.
1274 //
1275 // Revision 1.8  2008/04/10 15:15:32  bigatti
1276 // -- added  void myPushFront(rawc, rawpp)
1277 //
1278 // Revision 1.7  2007/12/05 12:11:07  bigatti
1279 // -- cleaning (mostly removing unused code)
1280 //
1281 // Revision 1.6  2007/12/04 14:27:07  bigatti
1282 // -- changed "log(pp, i)" into "exponent(pp, i)"
1283 //
1284 // Revision 1.5  2007/10/30 17:14:08  abbott
1285 // Changed licence from GPL-2 only to GPL-3 or later.
1286 // New version for such an important change.
1287 //
1288 // Revision 1.4  2007/05/22 22:45:14  abbott
1289 // Changed fn name IsUnit to IsInvertible.
1290 //
1291 // Revision 1.3  2007/05/21 14:50:56  bigatti
1292 // -- myPushFront and myPushBack now accept zero coefficient
1293 //
1294 // Revision 1.2  2007/03/12 16:00:29  bigatti
1295 // -- moved myLog(F, index) into unique implementation in SparsePolyRing
1296 //
1297 // Revision 1.1.1.1  2007/03/09 15:16:11  abbott
1298 // Imported files
1299 //
1300 // Revision 1.17  2007/03/08 18:22:30  cocoa
1301 // Just whitespace cleaning.
1302 //
1303 // Revision 1.16  2007/03/07 13:42:45  bigatti
1304 // -- removed useless argument and other minor changes
1305 //
1306 // Revision 1.15  2007/01/15 13:34:30  cocoa
1307 // -- added prefix "raw" to RawPtr arguments names
1308 //
1309 // Revision 1.14  2006/12/07 17:36:19  cocoa
1310 // -- migrated  myRemoveBigContent myContent myPowerSmallExp  into
1311 //    single implementation in SparsePolyRing
1312 // -- removed  content  from DistrMPolyClean(..)
1313 //
1314 // Revision 1.13  2006/11/23 18:01:53  cocoa
1315 // -- moved printing functions in unified implementation in SparsePolyRing
1316 // -- simplified "output(f)" for debugging only
1317 //
1318 // Revision 1.12  2006/11/22 15:11:36  cocoa
1319 // -- added #include "CoCoA/symbol.H"
1320 //
1321 // Revision 1.11  2006/11/21 18:09:24  cocoa
1322 // -- added myIsMonomial
1323 // -- implemented myIsOne, myIsMinusOne, myIsConstant, myIsIndet in SparsePolyRing
1324 // -- removed the 4 functions from DistrMPolyClean(..) and RingDistrMPolyClean(..)
1325 // -- changed all names of RawPtr arguments into "raw(..)"
1326 //
1327 // Revision 1.10  2006/11/14 17:17:13  cocoa
1328 // -- fixed coding convention "our"
1329 //
1330 // Revision 1.9  2006/11/09 17:46:58  cocoa
1331 // -- version 0.9712:
1332 // --   IdealImpl moved to SparsePolyRing from concrete rings
1333 // -- PolyList in GTypes is now vector<RingElem> (was list)
1334 // -- "my" coding convention applied to DistrMPolyClean
1335 //
1336 // Revision 1.8  2006/11/02 13:25:44  cocoa
1337 // Simplification of header files: the OpenMath classes have been renamed.
1338 // Many minor consequential changes.
1339 //
1340 // Revision 1.7  2006/10/16 23:18:59  cocoa
1341 // Corrected use of std::swap and various special swap functions.
1342 // Improved myApply memfn for homs of RingDistrMPolyCleanInlPP.
1343 //
1344 // Revision 1.6  2006/10/06 10:01:21  cocoa
1345 // Consequential changes from the modifications to the header files.
1346 //
1347 // Revision 1.5  2006/08/07 21:23:25  cocoa
1348 // Removed almost all publicly visible references to SmallExponent_t;
1349 // changed to long in all PPMonoid functions and SparsePolyRing functions.
1350 // DivMask remains to sorted out.
1351 //
1352 // Revision 1.4  2006/07/20 17:06:08  cocoa
1353 // -- moved myStdDeg into SparsePolyRing
1354 //
1355 // Revision 1.3  2006/06/22 14:07:18  cocoa
1356 // Minor cleaning and elimination of useless #includes.
1357 //
1358 // Revision 1.2  2006/06/08 16:45:28  cocoa
1359 // -- RingDistrMPolyClean*.H  have been "moved" into RingDistrMPolyClean*.C
1360 // -- some coding conventions fixed in DistrMPolyClean*
1361 // -- functions wdeg and CmpWDeg have a common implementation in SparsePolyRing
1362 //
1363 // Revision 1.1.1.1  2006/05/30 11:39:37  cocoa
1364 // Imported files
1365 //
1366 // Revision 1.11  2006/05/12 16:10:58  cocoa
1367 // Added OpenMathFwd.H, and tidied OpenMath.H.
1368 // Many consequential but trivial changes.
1369 //
1370 // Revision 1.10  2006/04/26 16:44:53  cocoa
1371 // -- myMul has now a single implementation in SparsePolyRing
1372 // -- myMul and mul in RingDistrMPolyClean* and DistrMPolyClean* have been disabled
1373 //
1374 // Revision 1.9  2006/03/27 12:21:25  cocoa
1375 // Minor silly changes to reduce number of complaints from some compiler or other.
1376 //
1377 // Revision 1.8  2006/03/17 18:08:51  cocoa
1378 // -- changed: mul --> myMulByPP
1379 //
1380 // Revision 1.7  2006/03/16 17:52:16  cocoa
1381 // -- changed: mul, div --> myMulByCoeff, myDivByCoeff
1382 //
1383 // Revision 1.6  2006/03/16 13:13:20  cocoa
1384 // -- added: CoCoA_ASSERT in DivLM
1385 //
1386 // Revision 1.5  2006/03/12 21:28:34  cocoa
1387 // Major check in after many changes
1388 //
1389 // Revision 1.4  2006/03/07 10:06:12  cocoa
1390 // -- fixed: PPMonoidElem LPP(f) now returns ConstRefPPMonoidElem
1391 //
1392 // Revision 1.3  2006/02/20 22:41:20  cocoa
1393 // All forms of the log function for power products now return SmallExponent_t
1394 // (instead of int).  exponents now resizes the vector rather than requiring
1395 // the user to pass in the correct size.
1396 //
1397 // Revision 1.2  2006/02/13 13:17:40  cocoa
1398 // -- fixed: "const PPMonoidElem&" --> "ConstRefPPMonoidElem"
1399 //
1400 // Revision 1.1.1.1  2005/10/17 10:46:54  cocoa
1401 // Imported files
1402 //
1403 // Revision 1.6  2005/10/12 15:52:09  cocoa
1404 // Completed test-RingFp1 and corrected/cleaned the SmallFp*
1405 // and RingFp* files.
1406 //
1407 // Some minor tidying elsewhere.
1408 //
1409 // Revision 1.5  2005/08/08 16:36:32  cocoa
1410 // Just checking in before going on holiday.
1411 // Don't really recall what changes have been made.
1412 // Added IsIndet function for RingElem, PPMonoidElem,
1413 // and a member function of OrdvArith.
1414 // Improved the way failed assertions are handled.
1415 //
1416 // Revision 1.4  2005/07/08 15:09:29  cocoa
1417 // Added new symbol class (to represent names of indets).
1418 // Integrated the new class into concrete polynomial rings
1419 // and PPMonoid -- many consequential changes.
1420 // Change ctors for the "inline" sparse poly rings: they no
1421 // longer expect a PPMonoid, but build their own instead
1422 // (has to be a PPMonoidOv).
1423 //
1424 // Revision 1.3  2005/07/01 16:08:16  cocoa
1425 // Friday check-in.  Major change to structure under PolyRing:
1426 // now SparsePolyRing and DUPolyRing are separated (in preparation
1427 // for implementing iterators).
1428 //
1429 // A number of other relatively minor changes had to be chased through
1430 // (e.g. IndetPower).
1431 //
1432 // Revision 1.2  2005/06/22 14:47:56  cocoa
1433 // PPMonoids and PPMonoidElems updated to mirror the structure
1434 // used for rings and RingElems.  Many consequential changes.
1435 //
1436 // Revision 1.1.1.1  2005/05/03 15:47:31  cocoa
1437 // Imported files
1438 //
1439 // Revision 1.5  2005/04/20 15:40:48  cocoa
1440 // Major change: modified the standard way errors are to be signalled
1441 // (now via a macro which records filename and line number).  Updated
1442 // documentation in error.txt accordingly.
1443 //
1444 // Improved the documentation in matrix.txt (still more work to be done).
1445 //
1446 // Revision 1.4  2005/04/19 14:06:04  cocoa
1447 // Added GPL and GFDL licence stuff.
1448 //
1449 // Revision 1.3  2005/02/11 16:45:24  cocoa
1450 // Removed the useless and misleading functions myInit and myKill
1451 // from the SmallFp*Impl classes; various consequential changes.
1452 //
1453 // Revision 1.2  2005/02/11 14:15:20  cocoa
1454 // New style ring elements and references to ring elements;
1455 // I hope I have finally got it right!
1456 //
1457 // Revision 1.1.1.1  2005/01/27 15:12:13  cocoa
1458 // Imported files
1459 //
1460 // Revision 1.13  2004/11/19 15:44:27  cocoa
1461 // Changed names of "casting" functions which convert a ring into
1462 // one with a more special structure (e.g. FractionField).  These
1463 // functions now have names starting with "As".  There were several
1464 // consequential changes.
1465 //
1466 // Revision 1.12  2004/11/12 16:25:57  cocoa
1467 // -- printing aligned with DistrMPolyCleanInlFpPP and DistrMPolyCleanInlPP
1468 //
1469 // Revision 1.11  2004/11/11 13:30:52  cocoa
1470 // -- minor changes for doxygen
1471 // -- changed: cout --> GlobalLogput()
1472 //
1473 // Revision 1.10  2004/11/11 11:56:09  cocoa
1474 // (1) Tidied makefiles, and introduced common.mki
1475 // (2) Improved several tests, and cleaned them so that they
1476 //     handle sanely any otherwise unhandled exceptions.
1477 //
1478 // Revision 1.9  2004/11/08 13:56:02  cocoa
1479 // -- changed calls to ZZ (after changes to ZZ.H)
1480 //
1481 // Revision 1.8  2004/11/02 15:59:11  cocoa
1482 // -- fixed: memory leak on summand (auto_ptr)
1483 //
1484 // Revision 1.7  2004/10/28 16:02:08  cocoa
1485 // -- changed one last PPOrdering::ExpvElem into SmallExponent_t
1486 //
1487 // Revision 1.6  2004/10/21 17:16:37  cocoa
1488 // Fairly major change: new OrdvArith namspace with various members,
1489 //   new global typedef  SmallExponent_t (defined in config.H).
1490 //
1491 // Revision 1.5  2004/07/20 15:04:06  cocoa
1492 // The next step in the new "ring element" conversion process:
1493 // handling the case of creating a "const RefRingElem" object
1494 // (since C++ refuses to do this properly itself).
1495 //
1496 // Revision 1.4  2004/05/27 16:14:02  cocoa
1497 // Minor revision for new coding conventions.
1498 //
1499 // Revision 1.3  2004/05/24 15:52:14  cocoa
1500 // Major update:
1501 //   new error mechanism
1502 //   many fixes
1503 //   RingHoms almost work now
1504 //   RingFloat much improved
1505 //
1506 // Revision 1.2  2004/01/28 16:27:00  cocoa
1507 // Added the necessary for CmpDeg to work.
1508 //
1509 // Revision 1.1  2003/11/21 14:33:55  cocoa
1510 // -- First Import
1511 //
1512