1 //   Copyright (c)  2005-2012,2014  John Abbott
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 #include "CoCoA/RingFpDouble.H"
19 
20 #include "CoCoA/BigIntOps.H"
21 #include "CoCoA/BigRat.H"
22 #include "CoCoA/FieldIdeal.H"
23 #include "CoCoA/GlobalManager.H"
24 #include "CoCoA/MemPool.H"
25 #include "CoCoA/OpenMath.H"
26 #include "CoCoA/QuotientRing.H"
27 #include "CoCoA/RingHom.H"
28 #include "CoCoA/RingZZ.H"
29 #include "CoCoA/SmallFpDoubleImpl.H"
30 #include "CoCoA/assert.H"
31 #include "CoCoA/convert.H"
32 #include "CoCoA/error.H"
33 #include "CoCoA/ideal.H"
34 
35 
36 #include <algorithm>
37 //using std::swap;         // only in mySwap
38 #include <iostream>
39 using std::ostream;        // only in myOutput
40 // #include <limits>  ---  included in MachineInt.H (included via BigRat.H)
41 using std::numeric_limits; // only in ctor
42 // #include <memory>  ---  included in MemPool.H
43 using std::unique_ptr;
44 // #include <vector>  ---  included in ideal.H
45 using std::vector;
46 
47 
48 namespace CoCoA
49 {
50 
51   class RingFpDoubleImpl: public QuotientRingBase
52   {
53   private: // data members
54     typedef SmallFpDoubleImpl::value_t value_t;
55     const unsigned long myModulus;
56     const SmallFpDoubleImpl myImpl;
57     mutable MemPool myMemMgr;       // MemPool must come *BEFORE* myZeroPtr and myOnePtr
58     unique_ptr<RingElem> myZeroPtr;  ///< Every ring stores its own zero.
59     unique_ptr<RingElem> myOnePtr;   ///< Every ring stores its own one.
60 
61   private: // auxiliary functions
62     static unsigned long PrincipalGen(const ideal& I); // used for arg checking in ctor
63     static value_t& import(RingElemRawPtr rawx);
64     static const value_t& import(RingElemConstRawPtr rawx);
65 
66   private:
67     RingFpDoubleImpl(const ideal& I, GlobalSettings::ResidueSetting ResidueChoice = DefaultResidueSetting()); // called only by NewRingFpDouble
68     ~RingFpDoubleImpl();
69     friend QuotientRing NewRingFpDouble(const MachineInt& p, GlobalSettings::ResidueSetting ResidueChoice);
70     friend QuotientRing NewRingFpDouble(const BigInt& P);
71     friend QuotientRing NewRingFpDouble(const ideal& I);
72   private:
73     RingFpDoubleImpl(const RingFpDoubleImpl&);            ///< NEVER DEFINED -- disallow copy construction
74     RingFpDoubleImpl& operator=(const RingFpDoubleImpl&); ///< NEVER DEFINED -- disallow assignment
75   public:
76 
77     // functions inherited by RingBase (ring.H)
78     //-- ring
79     virtual void myCharacteristic(BigInt& p) const;
80     virtual long myLogCardinality() const;
81     virtual bool IamCommutative() const;
82     virtual bool3 IamIntegralDomain3(bool) const;
83     virtual bool IamField() const;
84     virtual bool IamFiniteField() const;
85     virtual bool IamExact() const;
86     virtual void myOutputSelf(std::ostream& out) const;
87     virtual void myOutputSelf(OpenMathOutput& OMOut) const;
88     //-- RingElem: memory
89     virtual ConstRefRingElem myZero() const;
90     virtual ConstRefRingElem myOne() const;
91     using RingBase::myNew;    // disable warnings of overloading
92     using RingBase::myAssign; // disable warnings of overloading
93     virtual RingElemRawPtr myNew() const;
94     virtual RingElemRawPtr myNew(const MachineInt& n) const;
95     virtual RingElemRawPtr myNew(const BigInt& N) const;
96     virtual RingElemRawPtr myNew(ConstRawPtr rawx) const;
97     virtual void myDelete(RawPtr rawx) const;
98     //-- RingElem: assignments
99     virtual void myAssign(RawPtr rawlhs, ConstRawPtr rawx) const;
100     virtual void myAssign(RawPtr rawlhs, const MachineInt& n) const;
101     virtual void myAssign(RawPtr rawlhs, const BigInt& N) const;
102     virtual void myAssignZero(RawPtr rawlhs) const;
103     virtual void myRecvTwinFloat(RawPtr rawlhs, ConstRawPtr rawx) const;
104     virtual void mySwap(RawPtr rawx, RawPtr rawy) const;
105     //-- RingElem: arithmetic
106     virtual void myNegate(RawPtr rawlhs, ConstRawPtr rawx) const;
107     virtual void myAdd(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const;
108     virtual void mySub(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const;
109     virtual void myMul(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const;
110     virtual void myDiv(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const;
111     virtual void myGcd(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const; // lhs = gcd(x,y) in a field
112     //-- RingElem: queries
113     virtual bool myIsZero(ConstRawPtr rawx) const;
114     virtual bool myIsOne(ConstRawPtr rawx) const;
115     virtual bool myIsMinusOne(ConstRawPtr rawx) const;
116     virtual bool myIsEqual(ConstRawPtr rawx, ConstRawPtr rawy) const;
117     virtual bool myIsInteger(BigInt& N, ConstRawPtr rawx) const; ///< always true
118     virtual bool myIsRational(BigRat& Q, ConstRawPtr rawx) const;
119     virtual bool myIsDouble(double& d, ConstRawPtr rawx) const;
120     virtual bool myIsDivisible(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const;
121     virtual bool myIsInvertible(ConstRawPtr rawx) const;
122     virtual bool myIsZeroAddMul(RawPtr rawlhs, ConstRawPtr rawy, ConstRawPtr rawz) const;
123     virtual bool myIsZeroAddMul(RawPtr rawlhs, RawPtr /*rawtmp*/, ConstRawPtr rawy, ConstRawPtr rawz) const;
124     //-- RingElem: printing
125     virtual void myOutput(std::ostream& out, ConstRawPtr rawx) const;
126     virtual void myOutput(OpenMathOutput& OMOut, ConstRawPtr rawx) const;
127     virtual bool myIsPrintAtom(ConstRawPtr rawx) const;
128     virtual bool myIsPrintedWithMinus(ConstRawPtr rawx) const;
129     //-- ideal
130     virtual ideal myIdealCtor(const std::vector<RingElem>& gens) const;
131     //-- RingHom
132     virtual RingHom myCompose(const RingHom& phi, const RingHom& theta) const; // phi(theta(...))
133 
134     virtual bool myImageLiesInSubfield(const RingHom& phi) const;
135 
136     //-- protected in RingBase
137     virtual void myPowerSmallExp(RawPtr rawlhs, ConstRawPtr rawx, long n) const;
138     virtual void myPowerBigExp(RawPtr rawlhs, ConstRawPtr rawx, const BigInt& N) const; // lhs = x^N, N big, x not -1,0,1
139 
140     // functions inherited by QuotientRingBase (QuotientRing.H)
141     virtual RingElem myCanonicalRepr(ConstRawPtr rawx) const;
142     virtual void myReduction(RawPtr rawimage, ConstRawPtr rawarg) const;
143     virtual RingHom myInducedHomCtor(const RingHom& InducingHom) const;
144 
145 
146   private:
147     class InducedHomImpl: public RingHomBase
148     {
149     public:
150       InducedHomImpl(const QuotientRing& domain, const RingHom& InducingHom);
151       virtual void myApply(RingElemRawPtr rawimage, RingElemConstRawPtr rawarg) const;
IamPartial()152       virtual bool IamPartial() const { return false; }
153     };
154 
155   };
156 
157 
158 
import(RingElemRawPtr rawx)159   inline RingFpDoubleImpl::value_t& RingFpDoubleImpl::import(RingElemRawPtr rawx)
160   {
161     return *static_cast<value_t*>(rawx.myRawPtr());
162   }
163 
import(RingElemConstRawPtr rawx)164   inline const RingFpDoubleImpl::value_t& RingFpDoubleImpl::import(RingElemConstRawPtr rawx)
165   {
166     return *static_cast<const value_t*>(rawx.myRawPtr());
167   }
168 
169 
170   // Returns generator of I as a value_t; returns 0 if value is too large to fit.
PrincipalGen(const ideal & I)171   unsigned long RingFpDoubleImpl::PrincipalGen(const ideal& I)
172   {
173     if (IsZero(I)) return 0;
174     const BigInt GenI = ConvertTo<BigInt>(TidyGens(I)[0]);
175     unsigned long p;
176     if (!IsConvertible(p, GenI))  // check that the value of the principal generator will fit
177       return 0;
178     return p;
179   }
180 
181 
RingFpDoubleImpl(const ideal & I,GlobalSettings::ResidueSetting ResidueChoice)182   RingFpDoubleImpl::RingFpDoubleImpl(const ideal& I, GlobalSettings::ResidueSetting ResidueChoice):
183       QuotientRingBase(RingZZ(), I),  // confirms that I is an ideal of Z
184       myModulus(PrincipalGen(I)),
185       myImpl(myModulus, ResidueChoice),   // also checks that myModulus is a small prime
186       myMemMgr(SmallFpDoubleImpl::ourDatumSize, "RingFpDoubleImpl.myMemMgr")
187   {
188     myRefCountInc();  // this is needed for exception cleanliness, in case one of the lines below throws
189     myZeroPtr.reset(new RingElem(ring(this)));
190     myOnePtr.reset(new RingElem(ring(this), 1));
191     myRefCountZero();
192   }
193 
194 
~RingFpDoubleImpl()195   RingFpDoubleImpl::~RingFpDoubleImpl()
196   {}
197 
198 
myCharacteristic(BigInt & p)199   void RingFpDoubleImpl::myCharacteristic(BigInt& p) const
200   {
201     p = myModulus;
202   }
203 
204 
myLogCardinality()205   long RingFpDoubleImpl::myLogCardinality() const
206   {
207     return 1;
208   }
209 
210 
IamCommutative()211   bool RingFpDoubleImpl::IamCommutative() const
212   {
213     return true;
214   }
215 
216 
IamIntegralDomain3(bool)217   bool3 RingFpDoubleImpl::IamIntegralDomain3(bool) const
218   {
219     return true3;
220   }
221 
222 
IamField()223   bool RingFpDoubleImpl::IamField() const
224   {
225     return true;
226   }
227 
228 
IamFiniteField()229   bool RingFpDoubleImpl::IamFiniteField() const
230   {
231     return true;
232   }
233 
234 
IamExact()235   bool RingFpDoubleImpl::IamExact() const
236   {
237     return true;
238   }
239 
240 
myZero()241   ConstRefRingElem RingFpDoubleImpl::myZero() const
242   {
243     return *myZeroPtr;
244   }
245 
246 
myOne()247   ConstRefRingElem RingFpDoubleImpl::myOne() const
248   {
249     return *myOnePtr;
250   }
251 
252 
myNew()253   RingElemRawPtr RingFpDoubleImpl::myNew() const
254   {
255     value_t* ans = static_cast<value_t*>(myMemMgr.alloc());
256     *ans = 0;
257     return RingElemRawPtr(ans);
258   }
259 
260 
myNew(const MachineInt & n)261   RingElemRawPtr RingFpDoubleImpl::myNew(const MachineInt& n) const
262   {
263     value_t* ans = static_cast<value_t*>(myMemMgr.alloc());
264     *ans = myImpl.myReduce(n);
265     return RingElemRawPtr(ans);
266   }
267 
268 
myNew(const BigInt & N)269   RingElemRawPtr RingFpDoubleImpl::myNew(const BigInt& N) const
270   {
271     value_t* ans = static_cast<value_t*>(myMemMgr.alloc());
272     *ans = myImpl.myReduce(N);
273     return RingElemRawPtr(ans);
274   }
275 
276 
myNew(ConstRawPtr rawy)277   RingElemRawPtr RingFpDoubleImpl::myNew(ConstRawPtr rawy) const
278   {
279     value_t* ans = static_cast<value_t*>(myMemMgr.alloc());
280     *ans  = import(rawy);
281     return RingElemRawPtr(ans);
282   }
283 
284 
myDelete(RawPtr rawx)285   void RingFpDoubleImpl::myDelete(RawPtr rawx) const
286   {
287     myMemMgr.free(rawx.myRawPtr());
288   }
289 
290 
mySwap(RawPtr rawx,RawPtr rawy)291   void RingFpDoubleImpl::mySwap(RawPtr rawx, RawPtr rawy) const
292   {
293     std::swap(import(rawx), import(rawy));
294   }
295 
296 
myAssign(RawPtr rawlhs,ConstRawPtr rawx)297   void RingFpDoubleImpl::myAssign(RawPtr rawlhs, ConstRawPtr rawx) const
298   {
299     import(rawlhs) = import(rawx);
300   }
301 
302 
myAssign(RawPtr rawlhs,const MachineInt & n)303   void RingFpDoubleImpl::myAssign(RawPtr rawlhs, const MachineInt& n) const
304   {
305     import(rawlhs) = myImpl.myReduce(n);
306   }
307 
308 
myAssign(RawPtr rawlhs,const BigInt & N)309   void RingFpDoubleImpl::myAssign(RawPtr rawlhs, const BigInt& N) const
310   {
311     import(rawlhs) = myImpl.myReduce(N);
312   }
313 
314 
myAssignZero(RawPtr rawlhs)315   void RingFpDoubleImpl::myAssignZero(RawPtr rawlhs) const
316   {
317     import(rawlhs) = 0;
318   }
319 
320 
myRecvTwinFloat(RawPtr,ConstRawPtr)321   void RingFpDoubleImpl::myRecvTwinFloat(RawPtr /*rawlhs*/, ConstRawPtr /*rawx*/) const
322   {
323     CoCoA_THROW_ERROR(ERR::ShouldNeverGetHere, "RingFpDoubleImpl::myRecvTwinFloat");
324   }
325 
326 
myNegate(RawPtr rawlhs,ConstRawPtr rawx)327   void RingFpDoubleImpl::myNegate(RawPtr rawlhs, ConstRawPtr rawx) const
328   {
329     import(rawlhs) = myImpl.myNegate(import(rawx));
330   }
331 
332 
myAdd(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)333   void RingFpDoubleImpl::myAdd(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const
334   {
335     import(rawlhs) = myImpl.myAdd(import(rawx), import(rawy));
336   }
337 
338 
mySub(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)339   void RingFpDoubleImpl::mySub(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const
340   {
341     import(rawlhs) = myImpl.mySub(import(rawx), import(rawy));
342   }
343 
344 
myMul(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)345   void RingFpDoubleImpl::myMul(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const
346   {
347     import(rawlhs) = myImpl.myMul(import(rawx), import(rawy));
348   }
349 
350 
myDiv(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)351   void RingFpDoubleImpl::myDiv(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const
352   {
353     CoCoA_ASSERT(!myIsZero(rawy));
354     import(rawlhs) = myImpl.myDiv(import(rawx), import(rawy));
355   }
356 
357 
myIsDivisible(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)358   bool RingFpDoubleImpl::myIsDivisible(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const
359   {
360     if (myIsZero(rawy)) return false;
361     myDiv(rawlhs, rawx, rawy);
362     return true;
363   }
364 
365 
myIsInvertible(ConstRawPtr rawx)366   bool RingFpDoubleImpl::myIsInvertible(ConstRawPtr rawx) const
367   {
368     return !myIsZero(rawx);
369   }
370 
371 
myGcd(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)372   void RingFpDoubleImpl::myGcd(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const
373   {
374     myGcdInField(rawlhs, rawx, rawy);
375   }
376 
377 
myPowerSmallExp(RawPtr rawlhs,ConstRawPtr rawx,long n)378   void RingFpDoubleImpl::myPowerSmallExp(RawPtr rawlhs, ConstRawPtr rawx, long n) const  // assumes n > 1
379   {
380     // Assert that we have a genuinely non-trivial case.
381     CoCoA_ASSERT(n > 1);
382     CoCoA_ASSERT(!myIsZero(rawx) && !myIsOne(rawx) && !myIsMinusOne(rawx));
383     import(rawlhs) = myImpl.myPower(import(rawx), n);
384   }
385 
myPowerBigExp(RawPtr rawlhs,ConstRawPtr rawx,const BigInt & N)386   void RingFpDoubleImpl::myPowerBigExp(RawPtr rawlhs, ConstRawPtr rawx, const BigInt& N) const
387   {
388     // Assert that we have a genuinely non-trivial case.
389     CoCoA_ASSERT(N > 1);
390     CoCoA_ASSERT(!myIsZero(rawx) && !myIsOne(rawx) && !myIsMinusOne(rawx));
391     // Use Fermat's Little Theorem to reduce exponent...
392     import(rawlhs) = myImpl.myPower(import(rawx), N%(myModulus-1));
393   }
394 
395 
myOutput(ostream & out,ConstRawPtr rawx)396   void RingFpDoubleImpl::myOutput(ostream& out, ConstRawPtr rawx) const
397   {
398     if (!out) return;  // short-cut for bad ostreams
399     out << myImpl.myExport(import(rawx));
400   }
401 
402 
myIsPrintAtom(ConstRawPtr rawx)403   bool RingFpDoubleImpl::myIsPrintAtom(ConstRawPtr rawx) const
404   {
405     return myImpl.myExport(import(rawx)) >= 0;
406   }
407 
408 
myIsPrintedWithMinus(ConstRawPtr rawx)409   bool RingFpDoubleImpl::myIsPrintedWithMinus(ConstRawPtr rawx) const
410   {
411     return myImpl.myExport(import(rawx)) < 0;
412   }
413 
414 
myOutputSelf(ostream & out)415   void RingFpDoubleImpl::myOutputSelf(ostream& out) const
416   {
417     if (!out) return;  // short-cut for bad ostreams
418     out << "RingWithID(" << myID << ", \"ZZ/(" << myModulus << ")\")";
419   }
420 
421 
myOutputSelf(OpenMathOutput & OMOut)422   void RingFpDoubleImpl::myOutputSelf(OpenMathOutput& OMOut) const
423   {
424     OMOut->mySendApplyStart();
425     OMOut << OpenMathSymbol("setname2", "GFp");
426     OMOut << myModulus;
427     OMOut->mySendApplyEnd();
428   }
429 
430 
myOutput(OpenMathOutput & OMOut,ConstRawPtr rawx)431   void RingFpDoubleImpl::myOutput(OpenMathOutput& OMOut, ConstRawPtr rawx) const
432   {
433     OMOut << myImpl.myExport(import(rawx));
434   }
435 
436 
myIsZero(ConstRawPtr rawx)437   bool RingFpDoubleImpl::myIsZero(ConstRawPtr rawx) const
438   {
439     return (import(rawx) == 0);
440   }
441 
442 
myIsOne(ConstRawPtr rawx)443   bool RingFpDoubleImpl::myIsOne(ConstRawPtr rawx) const
444   {
445     return (import(rawx) == 1);
446   }
447 
448 
myIsMinusOne(ConstRawPtr rawx)449   bool RingFpDoubleImpl::myIsMinusOne(ConstRawPtr rawx) const
450   {
451     return (import(rawx) == myImpl.myReduce(-1));
452   }
453 
454 
myIsInteger(BigInt & N,ConstRawPtr rawx)455   bool RingFpDoubleImpl::myIsInteger(BigInt& N, ConstRawPtr rawx) const
456   {
457     N = myImpl.myExport(import(rawx));
458     return true;
459   }
460 
461 
myIsRational(BigRat & Q,ConstRawPtr rawx)462   bool RingFpDoubleImpl::myIsRational(BigRat& Q, ConstRawPtr rawx) const
463   {
464     Q = myImpl.myExport(import(rawx));
465     return true;
466   }
467 
468 
myIsDouble(double & d,ConstRawPtr rawx)469   bool RingFpDoubleImpl::myIsDouble(double& d, ConstRawPtr rawx) const
470   {
471     d = myImpl.myExport(import(rawx));
472     return true;
473   }
474 
475 
myIsZeroAddMul(RawPtr rawlhs,ConstRawPtr rawfact1,ConstRawPtr rawfact2)476   bool RingFpDoubleImpl::myIsZeroAddMul(RawPtr rawlhs, ConstRawPtr rawfact1, ConstRawPtr rawfact2) const
477   {
478     return myImpl.myIsZeroAddMul(import(rawlhs), import(rawfact1), import(rawfact2));
479   }
480 
481 
myIsZeroAddMul(RawPtr rawlhs,RawPtr,ConstRawPtr rawfact1,ConstRawPtr rawfact2)482   bool RingFpDoubleImpl::myIsZeroAddMul(RawPtr rawlhs, RawPtr /*rawtmp*/, ConstRawPtr rawfact1, ConstRawPtr rawfact2) const
483   {
484     return myImpl.myIsZeroAddMul(import(rawlhs), import(rawfact1), import(rawfact2));
485   }
486 
487 
myIsEqual(ConstRawPtr rawx,ConstRawPtr rawy)488   bool RingFpDoubleImpl::myIsEqual(ConstRawPtr rawx, ConstRawPtr rawy) const
489   {
490     return (import(rawx) == import(rawy));
491   }
492 
493 
494 
495 
myIdealCtor(const std::vector<RingElem> & gens)496   ideal RingFpDoubleImpl::myIdealCtor(const std::vector<RingElem>& gens) const
497   {
498     return NewFieldIdeal(ring(this), gens);
499   }
500 
501 
myCompose(const RingHom & phi,const RingHom & theta)502   RingHom RingFpDoubleImpl::myCompose(const RingHom& phi, const RingHom& theta) const
503   {
504     // No need to check compatibility -- it was checked when theta and phi were built
505     return RingHom(new InducedHomImpl(QuotientRing(this), phi(theta(myQuotientingHomCtor()))));
506   }
507 
508 
myImageLiesInSubfield(const RingHom & phi)509   bool RingFpDoubleImpl::myImageLiesInSubfield(const RingHom& phi) const
510   {
511     (void)(phi); // to avoid compiler warning about unused parameter
512     CoCoA_ASSERT(codomain(phi) == ring(this));
513     return true;
514   }
515 
516 
myCanonicalRepr(ConstRawPtr rawx)517   RingElem RingFpDoubleImpl::myCanonicalRepr(ConstRawPtr rawx) const
518   {
519     return RingElem(myReprRing, myImpl.myExport(import(rawx)));
520   }
521 
522 
myReduction(RawPtr rawimage,ConstRawPtr rawarg)523   void RingFpDoubleImpl::myReduction(RawPtr rawimage, ConstRawPtr rawarg) const
524   {
525     BigInt tmp;
526     CoCoA_ASSERT(myReprRing->myIsInteger(tmp, rawarg));
527     myReprRing->myIsInteger(tmp, rawarg);
528     import(rawimage) = myImpl.myReduce(tmp);
529   }
530 
531 
myInducedHomCtor(const RingHom & InducingHom)532   RingHom RingFpDoubleImpl::myInducedHomCtor(const RingHom& InducingHom) const
533   {
534     // Compatibility has already been checked (see InducedHom in QuotientRing.C)
535     CoCoA_ASSERT(IsZero(InducingHom(myModulus)));
536     return RingHom(new InducedHomImpl(QuotientRing(this), InducingHom));
537   }
538 
539 
540   //---------------------------------------------------------------------------
541   // Functions to do with ring homomorphisms
542 
543 
InducedHomImpl(const QuotientRing & domain,const RingHom & InducingHom)544   RingFpDoubleImpl::InducedHomImpl::InducedHomImpl(const QuotientRing& domain, const RingHom& InducingHom):
545       RingHomBase(domain, codomain(InducingHom))
546   { /* Compatibility already checked in InducedHom in QuotientRing.C */  }
547 
548 
myApply(RingElemRawPtr rawimage,RingElemConstRawPtr rawarg)549   void RingFpDoubleImpl::InducedHomImpl::myApply(RingElemRawPtr rawimage, RingElemConstRawPtr rawarg) const
550   {
551     BigInt tmp;  //??? wasteful new/delete
552     CoCoA_ASSERT(myDomain->myIsInteger(tmp, rawarg));
553     myDomain->myIsInteger(tmp, rawarg);  // must necessarily succeed
554     myCodomain->myAssign(rawimage, tmp);
555   }
556 
557 
558 
NewRingFpDouble(const MachineInt & p,GlobalSettings::ResidueSetting ResidueChoice)559   QuotientRing NewRingFpDouble(const MachineInt& p, GlobalSettings::ResidueSetting ResidueChoice)
560   {
561     return QuotientRing(new RingFpDoubleImpl(ideal(RingElem(RingZZ(), p)), ResidueChoice));
562   }
563 
NewRingFpDouble(const BigInt & P)564   QuotientRing NewRingFpDouble(const BigInt& P)
565   {
566     return QuotientRing(new RingFpDoubleImpl(ideal(RingElem(RingZZ(), P))));
567   }
568 
NewRingFpDouble(const ideal & I)569   QuotientRing NewRingFpDouble(const ideal& I)
570   {
571     if (!IsZZ(RingOf(I))) CoCoA_THROW_ERROR(ERR::IdealNotInRing, "NewRingFpDouble(I)");
572     return QuotientRing(new RingFpDoubleImpl(I));
573   }
574 
575 
IsGoodForRingFpDouble(const MachineInt & p)576   bool IsGoodForRingFpDouble(const MachineInt& p)
577   {
578     if (IsNegative(p) || !IsSignedLong(p)) return false;
579     const long n = AsSignedLong(p);
580     return SmallFpDoubleImpl::IsGoodCtorArg(n);
581   }
582 
IsGoodForRingFpDouble(const BigInt & P)583   bool IsGoodForRingFpDouble(const BigInt& P)
584   {
585     if (P <= 0) return false;
586     long p;
587     if (!IsConvertible(p, P)) return false;
588     return IsGoodForRingFpDouble(p);
589   }
590 
IsGoodForRingFpDouble(const ideal & I)591   bool IsGoodForRingFpDouble(const ideal& I)
592   {
593     if (!IsZZ(RingOf(I))) return false;
594     if (IsZero(I)) return false;
595     return IsGoodForRingFpDouble(ConvertTo<BigInt>(TidyGens(I)[0]));
596   }
597 
598 
599 } // end of namespace CoCoA
600 
601 
602 // RCS header/log
603 // $Header: /Volumes/Home_1/cocoa/cvs-repository/CoCoALib-0.99/src/AlgebraicCore/RingFpDouble.C,v 1.49 2020/06/17 15:49:26 abbott Exp $
604 // $Log: RingFpDouble.C,v $
605 // Revision 1.49  2020/06/17 15:49:26  abbott
606 // Summary: Changed CoCoA_ERROR into CoCoA_THROW_ERROR
607 //
608 // Revision 1.48  2020/02/11 16:56:41  abbott
609 // Summary: Corrected last update (see redmine 969)
610 //
611 // Revision 1.47  2020/02/11 16:12:19  abbott
612 // Summary: Added some checks for bad ostream (even to mem fns myOutput); see redmine 969
613 //
614 // Revision 1.46  2019/09/25 13:33:34  abbott
615 // Summary: Changed "compact" printed form of finite fields from FFp(...)  to ZZ/(...)
616 //
617 // Revision 1.45  2019/03/04 10:57:05  abbott
618 // Summary: Changed auto_ptr into unique_ptr
619 //
620 // Revision 1.44  2018/05/18 12:22:30  bigatti
621 // -- renamed IntOperations --> BigIntOps
622 //
623 // Revision 1.43  2017/09/06 11:56:29  abbott
624 // Summary: Changed ERR::SERIOUS into ERR::ShouldNeverGetHere
625 //
626 // Revision 1.42  2015/07/29 11:04:55  bigatti
627 // -- added space after comma in printing rings
628 //
629 // Revision 1.41  2014/07/30 14:08:57  abbott
630 // Summary: Changed name AmbientRing --> RingOf
631 // Author: JAA
632 //
633 // Revision 1.40  2014/07/28 16:04:49  abbott
634 // Summary: Renamed myQuotientingHom to myQuotientingHomCtor
635 // Author: JAA
636 //
637 // Revision 1.39  2014/07/28 15:49:35  abbott
638 // Summary: Redesign: ringhoms no longer cached in rings (caused ref count trouble)
639 // Author: JAA
640 //
641 // Revision 1.38  2014/07/04 13:08:08  bigatti
642 // -- RingID into RingWithID
643 //
644 // Revision 1.37  2014/07/02 16:35:04  bigatti
645 // -- new way of printing ring with ID
646 //
647 // Revision 1.36  2014/06/17 10:13:10  abbott
648 // Summary: Added (void)(phi) to avoid compiler warning about unused param
649 // Author: JAA
650 //
651 // Revision 1.35  2014/05/14 15:57:15  bigatti
652 // -- added "using" for clang with superpedantic flag
653 //
654 // Revision 1.34  2014/04/02 10:57:46  abbott
655 // Summary: Revised design of IamIntegralDomain3
656 // Author: JAA
657 //
658 // Revision 1.33  2014/03/27 17:17:31  abbott
659 // Summary: Added new fn IsIntegralDomain3 (and mem fn IamIntegralDomain3)
660 // Author: JAA
661 //
662 // Revision 1.32  2014/01/28 10:02:48  abbott
663 // Replaced some calls to IsInteger by calls to ConvertTo<BigInt>.
664 //
665 // Revision 1.31  2013/03/25 17:04:19  abbott
666 // Major clean-up of interface to SmallFpImpl/SmallFpLogImpl/SmallFpDoubleImpl
667 // (underlying impl remains much the same).  Removed lots of cruft.
668 // Consequential changes to RingFp* classes; small change to SparsePolyRing.
669 //
670 // Revision 1.30  2012/09/07 15:21:13  abbott
671 // First stage of revision of SmallFpImpl interface (and SmallFpLog, SmallFpDouble).
672 //
673 // Revision 1.29  2012/05/28 09:18:21  abbott
674 // Created IntOperations which gathers together all operations on
675 // integers (both big and small).  Many consequential changes.
676 //
677 // Revision 1.28  2012/04/27 15:04:10  abbott
678 // Added mem fns IamFiniteField & myLogCardinality.
679 //
680 // Revision 1.27  2012/03/16 14:43:48  bigatti
681 // -- re-sorted
682 //
683 // Revision 1.26  2012/02/10 10:28:08  bigatti
684 // -- changed RingZ.H, RingQ.H --> RingZZ.H, RingQQ.H
685 //
686 // Revision 1.25  2012/02/08 17:06:40  bigatti
687 // -- changed: Z,Q -> ZZ,QQ
688 // -- reordered member functions (to be completed)
689 //
690 // Revision 1.24  2012/01/30 23:20:48  abbott
691 // Realigned comments (I hope, CVS did something funny though).
692 //
693 // Revision 1.23  2012/01/25 13:33:51  bigatti
694 // -- added myIsZeroAddMul with 4 args
695 // -- some tidying
696 //
697 // Revision 1.22  2011/11/09 14:11:58  bigatti
698 // -- renamed MachineInteger --> MachineInt
699 //
700 // Revision 1.21  2011/08/24 10:28:49  bigatti
701 // -- renamed QQ --> BigRat
702 // -- sorted #include
703 //
704 // Revision 1.20  2011/08/14 15:52:16  abbott
705 // Changed ZZ into BigInt (phase 1: just the library sources).
706 //
707 // Revision 1.19  2011/06/23 16:04:47  abbott
708 // Added IamExact mem fn for rings.
709 // Added myRecvTwinFloat mem fn for rings.
710 // Added first imple of RingHom from RingTwinFloat to other rings.
711 //
712 // Revision 1.18  2011/05/24 14:54:29  abbott
713 // Consquential changes from removing several ctors for principal ideals.
714 //
715 // Revision 1.17  2011/05/20 19:26:05  abbott
716 // Updated SmallFp*Impl: removed all output-related fns (must use myExport instead).
717 //
718 // Revision 1.16  2011/05/20 09:45:04  abbott
719 // Harmonized RingFp, RingFpLog, RingFpDouble -- they are now almost ready to be merged into a single class!
720 //
721 // Revision 1.15  2011/05/19 14:38:27  abbott
722 // Updated small prime finite field impls to allow user to specify
723 // separately for each whether to use symmetric or non-negative
724 // residues for export operations (myExport and printing).
725 //
726 // Revision 1.14  2011/03/22 20:00:37  abbott
727 // Added IsGoodForXXX fns to test whether a given arg is suitable as
728 // characteristic for the given type of small prime finite field.
729 //
730 // Revision 1.13  2011/03/10 16:39:34  abbott
731 // Replaced (very many) size_t by long in function interfaces (for rings,
732 // PPMonoids and modules).  Also replaced most size_t inside fn defns.
733 //
734 // Revision 1.12  2010/10/06 14:10:24  abbott
735 // Added increments to the ref count in ring and PPMonoid ctors to make
736 // them exception safe.
737 //
738 // Revision 1.11  2009/12/11 11:46:32  abbott
739 // Changed fn  convert  into  IsConvertible.
740 // Added template procedure  convert.
741 // New version because change is not backward compatible.
742 //
743 // Revision 1.10  2009/09/25 14:01:11  abbott
744 // Cleaned up include directives.
745 //
746 // Revision 1.9  2009/09/24 16:22:29  abbott
747 // Tidied up include directives.  Removed some unnecessary "std::" prefixes.
748 //
749 // Revision 1.8  2009/07/02 16:32:11  abbott
750 // Consequential changes stemming from new class QQ, and modified interface to the member
751 // function RingBase::myIsRational.  Also some new conversion functions.
752 //
753 // Revision 1.7  2009/06/05 12:08:28  abbott
754 // Changed return type of operator%(ZZ,MachineInteger); it is now unsigned long
755 // instead of ZZ.
756 //
757 // Revision 1.6  2008/12/17 12:11:52  abbott
758 // Changed type from long to MachineInteger in operations which use a machine integer
759 // in place of a RingElem.  The change is "superficial" but affects many files.
760 //
761 // Revision 1.5  2007/10/30 17:14:07  abbott
762 // Changed licence from GPL-2 only to GPL-3 or later.
763 // New version for such an important change.
764 //
765 // Revision 1.4  2007/05/22 22:45:14  abbott
766 // Changed fn name IsUnit to IsInvertible.
767 //
768 // Revision 1.3  2007/05/21 12:44:25  abbott
769 // Changed impl of powering routine as a consequence of changed signature
770 // to the modulus operator for ZZ modulo machine integer.
771 //
772 // Revision 1.2  2007/03/23 18:38:42  abbott
773 // Separated the "convert" functions (and CheckedCast) into their own files.
774 // Many consequential changes.  Also corrected conversion to doubles.
775 //
776 // Revision 1.1.1.1  2007/03/09 15:16:11  abbott
777 // Imported files
778 //
779 // Revision 1.14  2007/03/08 18:22:29  cocoa
780 // Just whitespace cleaning.
781 //
782 // Revision 1.13  2007/03/08 10:23:29  bigatti
783 // -- CanonHom --> CanonicalHom
784 //
785 // Revision 1.12  2007/03/05 21:06:07  cocoa
786 // New names for homomorphism pseudo-ctors: removed the "New" prefix.
787 //
788 // Revision 1.11  2007/03/03 14:07:23  bigatti
789 // -- "foundations" renamed into "GlobalManager"
790 //
791 // Revision 1.10  2007/03/02 10:47:53  cocoa
792 // First stage of RingZ modifications -- tests do not compile currently, Anna will fix this.
793 //
794 // Revision 1.9  2007/01/17 12:32:39  cocoa
795 // Changed a few more "raw" variable names so that the code compiles fine
796 // also when CoCoA_DEBUG is set.
797 //
798 // Revision 1.8  2007/01/15 16:00:10  cocoa
799 // -- added prefix "raw" to RawPtr arguments names
800 // -- changed rhs into rawx, n, or N
801 //
802 // Revision 1.7  2007/01/13 14:14:34  cocoa
803 // Overhaul of RingHom code: it nows uses SmartPtrIRC, and printing is more logical.
804 // Have not yet updated the documentation.
805 //
806 // Revision 1.6  2006/11/08 16:21:59  cocoa
807 // Structural cleaning of RingHom; many consequential changes.
808 //
809 // Revision 1.5  2006/11/02 13:25:44  cocoa
810 // Simplification of header files: the OpenMath classes have been renamed.
811 // Many minor consequential changes.
812 //
813 // Revision 1.4  2006/10/16 23:18:59  cocoa
814 // Corrected use of std::swap and various special swap functions.
815 // Improved myApply memfn for homs of RingDistrMPolyInlPP.
816 //
817 // Revision 1.3  2006/10/06 14:04:14  cocoa
818 // Corrected position of #ifndef in header files.
819 // Separated CoCoA_ASSERT into assert.H from config.H;
820 // many minor consequential changes (have to #include assert.H).
821 // A little tidying of #include directives (esp. in Max's code).
822 //
823 // Revision 1.2  2006/10/06 10:15:52  cocoa
824 // In response to Susan's bug: a fiasco when compiling with CoCoA_MEMPOOL_DEBUG
825 // set wrongly.  Moved several implementation classes out of their header files
826 // into the implementation files.  Several functions had to be uninlined.
827 // Also corrected position of #include, etc.
828 //
829 // Revision 1.1.1.1  2006/05/30 11:39:37  cocoa
830 // Imported files
831 //
832 // Revision 1.7  2006/05/29 16:22:37  cocoa
833 // Third time lucky???
834 // Added myIsInteger member function to all rings (NYI for RingFloat).
835 //
836 // Revision 1.6  2006/05/12 16:10:58  cocoa
837 // Added OpenMathFwd.H, and tidied OpenMath.H.
838 // Many consequential but trivial changes.
839 //
840 // Revision 1.5  2006/04/21 15:01:36  cocoa
841 // Changed default implementation of RingBase::myGcd -- it now gives a SERIOUS
842 // error.  All fields must now handle a call to gcd explicitly: they can use
843 // the new myGcdInField function.  It's now cleaner than it was.
844 //
845 // Revision 1.4  2006/03/15 18:09:31  cocoa
846 // Changed names of member functions which print out their object
847 // into myOutputSelf -- hope this will appease the Intel C++ compiler.
848 //
849 // Revision 1.3  2006/03/14 15:01:49  cocoa
850 // Improved the implementation of ring member fns for computing powers.
851 // Should keep Intel C++ compiler quieter too.
852 //
853 // Revision 1.2  2006/03/12 21:28:33  cocoa
854 // Major check in after many changes
855 //
856 // Revision 1.1.1.1  2005/10/17 10:46:54  cocoa
857 // Imported files
858 //
859 // Revision 1.3  2005/10/14 15:25:07  cocoa
860 // Major tidying and cleaning to small prime finite fields.
861 // Several consequential changes.  Improved their documentation.
862 //
863 // Added Makefile and script to include/CoCoA/ directory to
864 // keep library.H up to date.
865 //
866 // Revision 1.2  2005/10/12 15:52:09  cocoa
867 // Completed test-RingFp1 and corrected/cleaned the SmallFp*
868 // and RingFp* files.
869 //
870 // Some minor tidying elsewhere.
871 //
872 // Revision 1.1  2005/10/11 16:37:30  cocoa
873 // Added new small prime finite field class (see RingFpDouble).
874 //
875 // Cleaned makefiles and configuration script.
876 //
877 // Tidied PPMonoid code (to eliminate compiler warnings).
878 //
879 // Fixed bug in RingFloat::myIsInteger.
880 //
881