1 //   Copyright (c)  2003-2011,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/RingQQ.H"
19 
20 #include "CoCoA/BigIntOps.H"
21 #include "CoCoA/BigRat.H"
22 #include "CoCoA/FieldIdeal.H"
23 #include "CoCoA/FractionField.H"
24 #include "CoCoA/GlobalManager.H"
25 #include "CoCoA/MemPool.H"
26 #include "CoCoA/OpenMath.H"
27 #include "CoCoA/RingHom.H"
28 #include "CoCoA/RingZZ.H"
29 #include "CoCoA/assert.H"
30 #include "CoCoA/error.H"
31 #include "CoCoA/ideal.H"
32 #include "CoCoA/utils-gmp.H"
33 
34 #include <memory>
35 using std::unique_ptr;
36 #include <cmath>
37 using std::ldexp;
38 #include <iostream>
39 using std::ostream;
40 #include <limits>
41 using std::numeric_limits;
42 #include <vector>
43 using std::vector;
44 
45 
46 namespace CoCoA
47 {
48 
49   class RingQQImpl: public FractionFieldBase
50   {
51   private:
52     typedef mpq_t value_t; // mpq_t is the actual type of the values in a RingQQImpl
53     static value_t& import(RingElemRawPtr rawx);
54     static const value_t& import(const RingElemConstRawPtr rawx);
55 
56   private: // data members
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:
62     RingQQImpl(const ring& ZZ);
63     RingQQImpl(const RingQQImpl&);           // NEVER DEFINED -- copy ctor disabled
64     RingQQImpl operator=(const RingQQImpl&); // NEVER DEFINED -- assignment disabled
65     ~RingQQImpl();
66     friend FractionField MakeUniqueInstanceOfRingQQ(const ring&); // the only function allowed to call the constructor
67     friend bool RingQQStillInUse(const FractionField& QQ);
68 
69   public:
70     typedef RingElemRawPtr RawPtr;
71     typedef RingElemConstRawPtr ConstRawPtr;
72 
73     // functions every ring must have
74     virtual ConstRefRingElem myZero() const;
75     virtual ConstRefRingElem myOne() const;
76     using RingBase::myNew;    // disable warnings of overloading
77     using RingBase::myAssign; // disable warnings of overloading
78     virtual RingElemRawPtr myNew() const;
79     virtual RingElemRawPtr myNew(const MachineInt& n) const;
80     virtual RingElemRawPtr myNew(const BigInt& n) const;
81     virtual RingElemRawPtr myNew(const BigRat& Q) const;
82     virtual RingElemRawPtr myNew(ConstRawPtr rawt) const;
83     virtual void myDelete(RawPtr rawx) const;                      // destroys x (incl all resources)
84     virtual void mySwap(RawPtr rawx, RawPtr rawy) const;                        // swap(x, y)
85     virtual void myAssign(RawPtr rawlhs, ConstRawPtr rawx) const;               // lhs = x
86     virtual void myAssign(RawPtr rawlhs, const MachineInt& n) const;        // lhs = n
87     virtual void myAssign(RawPtr rawlhs, const BigInt& N) const;                // lhs = N
88     virtual void myAssign(RawPtr rawlhs, const BigRat& Q) const;                    // lhs = Q
89     virtual void myAssignZero(RawPtr rawlhs) const;                             // lhs = 0
90     virtual void myRecvTwinFloat(RawPtr rawlhs, ConstRawPtr rawx) const;
91     virtual void myNegate(RawPtr rawlhs, ConstRawPtr rawx) const;               // lhs = -x
92     virtual void myAdd(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const;        // lhs = x+y
93     virtual void mySub(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const;        // lhs = x-y
94     virtual void myMul(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const;        // lhs = x*y
95     virtual void myDiv(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const;        // lhs = x/y
96     virtual bool myIsDivisible(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const;// lhs = x/y, if divisible
97     virtual bool myIsInvertible(ConstRawPtr rawx) const;                                // true iff x is invertible
98     virtual void myGcd(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const;        // lhs = gcd(x,y) in a field
99     virtual void myPowerSmallExp(RawPtr rawlhs, ConstRawPtr rawx, long n) const;// lhs = x^n, n>1, x not -1,0,1
100     virtual void myOutput(std::ostream& out, ConstRawPtr rawx) const;                   // out << x
101     virtual bool myIsPrintAtom(ConstRawPtr rawx) const;                                 // x^n may be printed without parentheses
102     virtual bool myIsPrintedWithMinus(ConstRawPtr rawx) const;
myOutputSelf(std::ostream & out)103     virtual void myOutputSelf(std::ostream& out) const       { out << "QQ"; }
myOutputSelfShort(std::ostream & out)104     virtual void myOutputSelfShort(std::ostream& out) const  { out << "QQ"; }
105     virtual void myOutputSelfLong(std::ostream& out) const;
106     virtual void myOutputSelf(OpenMathOutput& OMOut) const;                       // OMOut << R
107     virtual void myOutput(OpenMathOutput& OMOut, ConstRawPtr rawx) const;         // OMOut << x
108     virtual bool myIsZero(ConstRawPtr rawx) const;                                // x == 0
109     virtual bool myIsOne(ConstRawPtr rawx) const;                                 // x == 1
110     virtual bool myIsMinusOne(ConstRawPtr rawx) const;                            // x == -1
111     virtual bool myIsInteger(BigInt& N, ConstRawPtr rawx) const;                  // true iff x is integer
112     virtual bool myIsRational(BigRat& Q, ConstRawPtr rawx) const;                 // true iff x is rational
113     virtual bool myIsDouble(double& d, ConstRawPtr rawx) const;                   // false iff x overflows
114     // Use default definition myIsZeroAddMul (see ring.C)
115     virtual bool myIsEqual(ConstRawPtr rawx, ConstRawPtr rawy) const;             // x == y
116     virtual int myCmp(ConstRawPtr rawx, ConstRawPtr rawy) const;                  // result is <0, =0, >0 according as x<y, x=y, x>y
117     virtual int myCmpAbs(ConstRawPtr rawx, ConstRawPtr rawy) const;               // equiv to myCmp(abs(x),abs(y))
118     virtual int mySign(ConstRawPtr rawx) const;                                   // -1,0,+1 according as x <0,=0,>0
119     virtual BigInt myFloor(ConstRawPtr rawx) const;                               // floor(x)
120     virtual BigInt myCeil(ConstRawPtr rawx) const;                                // ceil(x)
121     virtual BigInt myNearestInt(ConstRawPtr rawx) const;                          // NearestInt(x)
122 
123     virtual ideal myIdealCtor(const std::vector<RingElem>& gens) const;
124 
125     virtual RingHom myCompose(const RingHom& phi, const RingHom& theta) const; // phi(theta(...))
126 
127     virtual bool myImageLiesInSubfield(const RingHom& phi) const;
128 
129     // functions special to a FractionField
130     virtual ConstRawPtr myRawNum(ConstRawPtr rawq) const;  ///< result belongs to BaseRing!!
131     virtual ConstRawPtr myRawDen(ConstRawPtr rawq) const;  ///< result belongs to BaseRing!!
132     virtual RingHom myEmbeddingHomCtor() const;
133     virtual RingHom myInducedHomCtor(const RingHom&) const;
134 
135 
136   private:
137     class InducedHomImpl: public RingHomBase
138     {
139     public:
140       InducedHomImpl(const FractionField& domain, const RingHom& phi);
141       void myApply(RawPtr rawimage, ConstRawPtr rawarg) const;
IamPartial()142       bool IamPartial() const { return !IsZero(characteristic(myCodomain)) || !IsField(myCodomain); }
143     private:
144       RingHom myInducingHomValue;
145     };
146 
147   };
148 
149 
150   // These two inline fns are used only in this file.
import(RingElemRawPtr rawx)151   inline RingQQImpl::value_t& RingQQImpl::import(RingElemRawPtr rawx)
152   {
153     return *static_cast<value_t*>(rawx.myRawPtr());
154   }
155 
import(RingElemConstRawPtr rawx)156   inline const RingQQImpl::value_t& RingQQImpl::import(RingElemConstRawPtr rawx)
157   {
158     return *static_cast<const value_t*>(rawx.myRawPtr());
159   }
160 
161 
162 
RingQQImpl(const ring & ZZ)163   RingQQImpl::RingQQImpl(const ring& ZZ):
164       FractionFieldBase(ZZ),
165       myMemMgr(sizeof(value_t), "RingQQImpl.myMemMgr")
166   {
167     CoCoA_ASSERT(IsZZ(ZZ));
168     myRefCountInc();  // this is needed for exception cleanliness, in case one of the lines below throws
169     myZeroPtr.reset(new RingElem(ring(this)));
170     myOnePtr.reset(new RingElem(ring(this), 1));
171     myRefCountZero();
172   }
173 
174 
~RingQQImpl()175   RingQQImpl::~RingQQImpl()
176   {}
177 
178 
myZero()179   ConstRefRingElem RingQQImpl::myZero() const
180   {
181     return *myZeroPtr;
182   }
183 
184 
myOne()185   ConstRefRingElem RingQQImpl::myOne() const
186   {
187     return *myOnePtr;
188   }
189 
190 
myNew()191   RingElemRawPtr RingQQImpl::myNew() const
192   {
193     value_t* ans = static_cast<value_t*>(myMemMgr.alloc());
194     mpq_init(*ans);
195     return RingElemRawPtr(ans);
196   }
197 
198 
myNew(const MachineInt & n)199   RingElemRawPtr RingQQImpl::myNew(const MachineInt& n) const
200   {
201     value_t* ans = static_cast<value_t*>(myMemMgr.alloc());
202     mpq_init(*ans);
203     if (IsNegative(n))
204       mpq_set_si(*ans, AsSignedLong(n), 1);
205     else
206       mpq_set_ui(*ans, AsUnsignedLong(n), 1);
207     return RingElemRawPtr(ans);
208   }
209 
210 
myNew(const BigInt & N)211   RingElemRawPtr RingQQImpl::myNew(const BigInt& N) const
212   {
213     value_t* ans = static_cast<value_t*>(myMemMgr.alloc());
214     mpq_init(*ans);
215     mpq_set_z(*ans, mpzref(N));
216     return RingElemRawPtr(ans);
217   }
218 
219 
myNew(const BigRat & Q)220   RingElemRawPtr RingQQImpl::myNew(const BigRat& Q) const
221   {
222     value_t* ans = static_cast<value_t*>(myMemMgr.alloc());
223     mpq_init(*ans);
224     mpq_set(*ans, mpqref(Q));
225     return RingElemRawPtr(ans);
226   }
227 
228 
myNew(ConstRawPtr rawcopy)229   RingElemRawPtr RingQQImpl::myNew(ConstRawPtr rawcopy) const
230   {
231     value_t* ans = static_cast<value_t*>(myMemMgr.alloc());
232     mpq_init(*ans);
233     mpq_set(*ans, import(rawcopy));
234     return RingElemRawPtr(ans);
235   }
236 
237 
myDelete(RawPtr rawx)238   void RingQQImpl::myDelete(RawPtr rawx) const
239   {
240     mpq_clear(import(rawx));
241     myMemMgr.free(rawx.myRawPtr());
242   }
243 
244 
mySwap(RawPtr rawx,RawPtr rawy)245   void RingQQImpl::mySwap(RawPtr rawx, RawPtr rawy) const
246   {
247     mpq_swap(import(rawx), import(rawy));
248   }
249 
250 
myAssign(RawPtr rawlhs,ConstRawPtr rawx)251   void RingQQImpl::myAssign(RawPtr rawlhs, ConstRawPtr rawx) const
252   {
253     mpq_set(import(rawlhs), import(rawx));
254   }
255 
256 
myAssign(RawPtr rawlhs,const MachineInt & n)257   void RingQQImpl::myAssign(RawPtr rawlhs, const MachineInt& n) const
258   {
259     if (IsNegative(n))
260       mpq_set_si(import(rawlhs), AsSignedLong(n), 1);
261     else
262       mpq_set_ui(import(rawlhs), AsUnsignedLong(n), 1);
263   }
264 
265 
myAssign(RawPtr rawlhs,const BigInt & N)266   void RingQQImpl::myAssign(RawPtr rawlhs, const BigInt& N) const
267   {
268     mpq_set_z(import(rawlhs), mpzref(N));
269   }
270 
271 
myAssign(RawPtr rawlhs,const BigRat & Q)272   void RingQQImpl::myAssign(RawPtr rawlhs, const BigRat& Q) const
273   {
274     mpq_set(import(rawlhs), mpqref(Q));
275   }
276 
277 
myAssignZero(RawPtr rawlhs)278   void RingQQImpl::myAssignZero(RawPtr rawlhs) const
279   {
280     mpq_set_ui(import(rawlhs), 0, 1);
281   }
282 
283 
myRecvTwinFloat(RawPtr,ConstRawPtr)284   void RingQQImpl::myRecvTwinFloat(RawPtr /*rawlhs*/, ConstRawPtr /*rawx*/) const
285   {
286     CoCoA_THROW_ERROR(ERR::ShouldNeverGetHere, "RingQQImpl::myRecvTwinFloat");
287   }
288 
myNegate(RawPtr rawlhs,ConstRawPtr rawx)289   void RingQQImpl::myNegate(RawPtr rawlhs, ConstRawPtr rawx) const
290   {
291     mpq_neg(import(rawlhs), import(rawx));
292   }
293 
294 
myAdd(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)295   void RingQQImpl::myAdd(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const
296   {
297     mpq_add(import(rawlhs), import(rawx), import(rawy));
298   }
299 
300 
mySub(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)301   void RingQQImpl::mySub(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const
302   {
303     mpq_sub(import(rawlhs), import(rawx), import(rawy));
304   }
305 
306 
myMul(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)307   void RingQQImpl::myMul(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const
308   {
309     mpq_mul(import(rawlhs), import(rawx), import(rawy));
310   }
311 
312 
myDiv(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)313   void RingQQImpl::myDiv(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const
314   {
315     CoCoA_ASSERT(!myIsZero(rawy));
316     mpq_div(import(rawlhs), import(rawx), import(rawy));
317   }
318 
319 
myIsDivisible(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)320   bool RingQQImpl::myIsDivisible(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const
321   {
322     if (myIsZero(rawy)) return false;
323     mpq_div(import(rawlhs), import(rawx), import(rawy));
324     return true;
325   }
326 
327 
myIsInvertible(ConstRawPtr rawx)328   bool RingQQImpl::myIsInvertible(ConstRawPtr rawx) const
329   {
330     return !myIsZero(rawx);
331   }
332 
333 
myGcd(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)334   void RingQQImpl::myGcd(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const
335   {
336     myGcdInField(rawlhs, rawx, rawy);
337   }
338 
339 
myPowerSmallExp(RawPtr rawlhs,ConstRawPtr rawx,long n)340   void RingQQImpl::myPowerSmallExp(RawPtr rawlhs, ConstRawPtr rawx, long n) const
341   {
342     // Assert that we have a genuinely non-trivial case.
343     CoCoA_ASSERT(n > 1);
344     CoCoA_ASSERT(!myIsZero(rawx) && !myIsOne(rawx) && !myIsMinusOne(rawx));
345     mpz_pow_ui(mpq_numref(import(rawlhs)), mpq_numref(import(rawx)), n);
346     mpz_pow_ui(mpq_denref(import(rawlhs)), mpq_denref(import(rawx)), n);
347   }
348 
349 
myOutput(std::ostream & out,ConstRawPtr rawx)350   void RingQQImpl::myOutput(std::ostream& out, ConstRawPtr rawx) const
351   {
352     if (!out) return;  // short-cut for bad ostreams
353     const int base = 10;
354     const size_t BufferSize = 3 + mpz_sizeinbase(mpq_numref(import(rawx)), base)
355                                 + mpz_sizeinbase(mpq_denref(import(rawx)), base);
356     vector<char> buffer(BufferSize);
357     mpq_get_str(&buffer[0], base, import(rawx));
358     out << &buffer[0];
359   }
360 
361 
myIsPrintAtom(ConstRawPtr rawx)362   bool RingQQImpl::myIsPrintAtom(ConstRawPtr rawx) const
363   {
364     return (mpz_cmp_si(mpq_denref(import(rawx)), 1)==0 && mpq_sgn(import(rawx)) >= 0);
365   }
366 
367 
myIsPrintedWithMinus(ConstRawPtr rawx)368   bool RingQQImpl::myIsPrintedWithMinus(ConstRawPtr rawx) const
369   {
370     return (mpq_sgn(import(rawx)) < 0);
371   }
372 
373 
myOutputSelfLong(ostream & out)374   void RingQQImpl::myOutputSelfLong(ostream& out) const
375   {
376     if (!out) return;  // short-cut for bad ostreams
377     out << "RingWithID(" << myID << ", \"QQ\")";
378   }
379 
380 
myOutputSelf(OpenMathOutput & OMOut)381   void RingQQImpl::myOutputSelf(OpenMathOutput& OMOut) const
382   {
383     OMOut << OpenMathSymbol("setname1", "QQ");
384   }
385 
386 
myOutput(OpenMathOutput & OMOut,ConstRawPtr rawx)387   void RingQQImpl::myOutput(OpenMathOutput& OMOut, ConstRawPtr rawx) const
388   {
389     OMOut->mySendApplyStart();
390     OMOut << OpenMathSymbol("cocoa", "NormalizedRational");
391     OMOut << BigIntFromMPZ(mpq_numref(import(rawx)))
392           << BigIntFromMPZ(mpq_denref(import(rawx)));
393     OMOut->mySendApplyEnd();
394   }
395 
396 
myIsZero(ConstRawPtr rawx)397   bool RingQQImpl::myIsZero(ConstRawPtr rawx) const
398   {
399     return mpq_sgn(import(rawx)) == 0;
400   }
401 
402 
myIsOne(ConstRawPtr rawx)403   bool RingQQImpl::myIsOne(ConstRawPtr rawx) const
404   {
405     return mpq_cmp_ui(import(rawx), 1, 1) == 0;
406   }
407 
408 
myIsMinusOne(ConstRawPtr rawx)409   bool RingQQImpl::myIsMinusOne(ConstRawPtr rawx) const
410   {
411     return mpq_cmp_si(import(rawx), -1, 1) == 0;
412   }
413 
414 
myIsInteger(BigInt & N,ConstRawPtr rawx)415   bool RingQQImpl::myIsInteger(BigInt& N, ConstRawPtr rawx) const
416   {
417     CoCoA_ASSERT(mpz_sgn(mpq_denref(import(rawx))) > 0);
418     if (myIsZero(rawx)) { N = 0; return true; }
419     if (mpz_cmp_ui(mpq_denref(import(rawx)), 1) != 0) return false;
420     mpz_set(mpzref(N), mpq_numref(import(rawx)));
421     return true;
422   }
423 
424 
myIsRational(BigRat & Q,ConstRawPtr rawx)425   bool RingQQImpl::myIsRational(BigRat& Q, ConstRawPtr rawx) const
426   {
427     mpq_set(mpqref(Q), import(rawx));
428     return true;
429   }
430 
431   // MISSING FROM GMP-5.0.2
mpq_get_d_2exp(signed long int * e,mpq_srcptr q)432   double mpq_get_d_2exp(signed long int* e, mpq_srcptr q)
433   {
434     long expnum, expden;
435     double mantnum, mantden;
436     if (mpq_sgn(q) == 0) { e = 0; return 0.0; }
437     mantnum = mpz_get_d_2exp(&expnum, mpq_numref(q)); // ???expnum could overflow
438     mantden = mpz_get_d_2exp(&expden, mpq_denref(q)); // ???expden could overflow
439     *e = expnum-expden;
440     double ans = mantnum/mantden;
441     if (ans >= 1) { ans /= 2; ++*e; } //???overflow in e???
442     return ans;
443   }
444 
myIsDouble(double & d,ConstRawPtr rawx)445   bool RingQQImpl::myIsDouble(double& d, ConstRawPtr rawx) const
446   {
447     long exp = 0; // pointless initialization to keep compiler quiet
448     d = mpq_get_d_2exp(&exp, import(rawx)); // BUG, ignore possible overflow in exp
449     if (numeric_limits<double>::radix != 2) CoCoA_THROW_ERROR(ERR::NYI, "RingQQImpl::myIsDouble");
450     if (exp < numeric_limits<double>::min_exponent) { d=0; return true; }  // ???false also for underflow???
451     if (exp > numeric_limits<double>::max_exponent) return false;
452     d = ldexp(d,exp);
453     return true;
454   }
455 
456 
myIsEqual(ConstRawPtr rawx,ConstRawPtr rawy)457   bool RingQQImpl::myIsEqual(ConstRawPtr rawx, ConstRawPtr rawy) const
458   {
459     return mpq_cmp(import(rawx), import(rawy)) == 0;
460   }
461 
462 
myCmp(ConstRawPtr rawx,ConstRawPtr rawy)463   int RingQQImpl::myCmp(ConstRawPtr rawx, ConstRawPtr rawy) const
464   {
465     return sign(mpq_cmp(import(rawx), import(rawy)));
466   }
467 
468 
myCmpAbs(ConstRawPtr rawx,ConstRawPtr rawy)469   int RingQQImpl::myCmpAbs(ConstRawPtr rawx, ConstRawPtr rawy) const
470   {
471     return sign(mpq_cmpabs(import(rawx), import(rawy)));
472   }
473 
474 
mySign(ConstRawPtr rawx)475   int RingQQImpl::mySign(ConstRawPtr rawx) const
476   {
477     return mpq_sgn(import(rawx));
478   }
479 
480 
myFloor(ConstRawPtr rawx)481   BigInt RingQQImpl::myFloor(ConstRawPtr rawx) const
482   {
483     BigInt N;
484     mpz_fdiv_q(mpzref(N), mpq_numref(import(rawx)), mpq_denref(import(rawx)));
485     return N;
486   }
487 
myCeil(ConstRawPtr rawx)488   BigInt RingQQImpl::myCeil(ConstRawPtr rawx) const
489   {
490     BigInt N;
491     mpz_cdiv_q(mpzref(N), mpq_numref(import(rawx)), mpq_denref(import(rawx)));
492     return N;
493   }
494 
myNearestInt(ConstRawPtr rawx)495   BigInt RingQQImpl::myNearestInt(ConstRawPtr rawx) const
496   {
497     BigInt N;
498     mpq_round(mpzref(N), import(rawx));
499     return N;
500   }
501 
502 
myIdealCtor(const std::vector<RingElem> & gens)503   ideal RingQQImpl::myIdealCtor(const std::vector<RingElem>& gens) const
504   {
505     return NewFieldIdeal(ring(this), gens);
506   }
507 
508 
myCompose(const RingHom & phi,const RingHom & theta)509   RingHom RingQQImpl::myCompose(const RingHom& phi, const RingHom& theta) const
510   {
511     return myInducedHomCtor(phi(theta(myEmbeddingHomCtor())));
512   }
513 
myImageLiesInSubfield(const RingHom & phi)514   bool RingQQImpl::myImageLiesInSubfield(const RingHom& phi) const
515   {
516     (void)(phi); // to avoid compiler warning about unused parameter
517     CoCoA_ASSERT(codomain(phi) == ring(this));
518     return true;
519   }
520 
521 
522   //--------------------------------------------------
523   // Below are functions special to a FractionField
524 
525   // const ring& RingQQImpl::myBaseRing() const
526   // {
527   //   return myZZ;
528   // }
529 
530 
myRawNum(ConstRawPtr rawq)531   RingElemConstRawPtr RingQQImpl::myRawNum(ConstRawPtr rawq) const
532   {
533     return RingElemConstRawPtr(mpq_numref(import(rawq)));
534   }
535 
myRawDen(ConstRawPtr rawq)536   RingElemConstRawPtr RingQQImpl::myRawDen(ConstRawPtr rawq) const
537   {
538     return RingElemConstRawPtr(mpq_denref(import(rawq)));
539   }
540 
541 
myEmbeddingHomCtor()542   RingHom RingQQImpl::myEmbeddingHomCtor() const
543   {
544     return RingHom(ZZEmbeddingHom(myBaseRing(), FractionField(this)));
545   }
546 
547 
myInducedHomCtor(const RingHom & phi)548   RingHom RingQQImpl::myInducedHomCtor(const RingHom& phi) const
549   {
550     return RingHom(new InducedHomImpl(FractionField(this), phi));
551   }
552 
553 
554 
InducedHomImpl(const FractionField & domain,const RingHom & phi)555   RingQQImpl::InducedHomImpl::InducedHomImpl(const FractionField& domain, const RingHom& phi):
556       RingHomBase(domain, codomain(phi)),
557       myInducingHomValue(phi)
558   { /*??? MUST CHECK IT MAKES SENSE -- e.g.  given ZZ->ZZ[x] ker=0, but cannot do QQ->ZZ[x]*/ }
559 
560 
myApply(RawPtr rawimage,ConstRawPtr rawarg)561   void RingQQImpl::InducedHomImpl::myApply(RawPtr rawimage, ConstRawPtr rawarg) const
562   {
563     RingHom phi = myInducingHomValue;
564     const FractionField QQ = myDomain;
565     CoCoA_ASSERT(domain(phi) == BaseRing(QQ));
566     ring ZZ = BaseRing(QQ);
567     RingElemAlias N(ZZ, QQ->myRawNum(rawarg));
568     RingElemAlias D(ZZ, QQ->myRawDen(rawarg));
569 
570     RingElem ImN = phi(N);
571     RingElem ImD = phi(D);
572 
573     if (!myCodomain->myIsDivisible(rawimage, raw(ImN), raw(ImD)))
574       CoCoA_THROW_ERROR(ERR::BadPartialRingHomArg, "RingQQImpl::InducedHomImpl::myApply");
575   }
576 
577 
578 
579   // This fn is declared in GlobalManager.C and called only by ctor of CoCoA::GlobalManager.
MakeUniqueInstanceOfRingQQ(const ring & GlobalZZ)580   FractionField MakeUniqueInstanceOfRingQQ(const ring& GlobalZZ)
581   {
582     return FractionField(new RingQQImpl(GlobalZZ));
583   }
584 
585 
RingQQ()586   const FractionField& RingQQ()
587   {
588     if (GlobalManager::ourGlobalDataPtr == 0)
589       CoCoA_THROW_ERROR(ERR::NoGlobalMgr, "RingQQ()");
590     return GlobalManager::ourGlobalDataPtr->myRingQQ();
591   }
592 
593 
IsQQ(const ring & R)594   bool IsQQ(const ring& R)
595   {
596     return dynamic_cast<const RingQQImpl*>(R.myRawPtr()) != 0;
597   }
598 
599 
QQEmbeddingHom(const ring & codomain)600   RingHom QQEmbeddingHom(const ring& codomain)
601   {
602     return InducedHom(RingQQ(), ZZEmbeddingHom(codomain));
603   }
604 
605 
606   // This fn is used only in the dtor for GlobalManager.
RingQQStillInUse(const FractionField & QQ)607   bool RingQQStillInUse(const FractionField& QQ)
608   {
609     const RingQQImpl* QQptr = dynamic_cast<const RingQQImpl*>(QQ.myRawPtr());
610 #ifdef CoCoA_DEBUG
611     if (QQptr->myRefCount() > 1)
612       std::cerr << "ERROR!!!  RingQQ refcount = " << QQptr->myRefCount() << " but should be 1." << std::endl;
613 #endif
614     return QQptr->myRefCount() > 1; // copy in GlobalManager
615   }
616 
617 
618 } // end of namespace CoCoA
619 
620 
621 // RCS header/log in the next few lines
622 // $Header: /Volumes/Home_1/cocoa/cvs-repository/CoCoALib-0.99/src/AlgebraicCore/RingQQ.C,v 1.31 2020/06/17 15:49:26 abbott Exp $
623 // $Log: RingQQ.C,v $
624 // Revision 1.31  2020/06/17 15:49:26  abbott
625 // Summary: Changed CoCoA_ERROR into CoCoA_THROW_ERROR
626 //
627 // Revision 1.30  2020/02/11 16:56:42  abbott
628 // Summary: Corrected last update (see redmine 969)
629 //
630 // Revision 1.29  2020/02/11 16:12:19  abbott
631 // Summary: Added some checks for bad ostream (even to mem fns myOutput); see redmine 969
632 //
633 // Revision 1.28  2019/03/04 10:59:04  abbott
634 // Summary: Changed auto_ptr into unique_ptr
635 //
636 // Revision 1.27  2018/05/18 12:22:30  bigatti
637 // -- renamed IntOperations --> BigIntOps
638 //
639 // Revision 1.26  2018/04/20 18:51:25  abbott
640 // Summary: Changed ctors for BigInt/BigRat from string or from MPZ/MPQ
641 //
642 // Revision 1.25  2017/09/06 11:56:29  abbott
643 // Summary: Changed ERR::SERIOUS into ERR::ShouldNeverGetHere
644 //
645 // Revision 1.24  2017/05/09 13:51:30  bigatti
646 // -- changed BadRingHomArg2 --> BadPartialRingHomArg
647 //
648 // Revision 1.23  2016/03/25 20:42:37  abbott
649 // Summary: Renamed utils_gmp to utils-gmp
650 //
651 // Revision 1.22  2016/03/25 20:06:49  abbott
652 // Summary: Introduced new mem fns myCeil and myNearestInt; impls in ZZ, QQ, & TwinFloat. Renamed NearestInteger to NearestInt.
653 //
654 // Revision 1.21  2015/11/23 18:22:26  abbott
655 // Summary: Changed arg name GlobalZ into GlobalZZ
656 //
657 // Revision 1.20  2015/07/29 11:04:55  bigatti
658 // -- added space after comma in printing rings
659 //
660 // Revision 1.19  2014/07/28 16:05:18  abbott
661 // Summary: Renamed myEmbeddingHom to myEmbeddingHomCtor
662 // Author: JAA
663 //
664 // Revision 1.18  2014/07/28 15:50:59  abbott
665 // Summary: Redesign: ringhoms no longer cached in rings (caused ref count trouble)
666 // Author: JAA
667 //
668 // Revision 1.17  2014/07/11 15:37:00  bigatti
669 // -- added myOutputSelfShort and myOutputSelfLong
670 //
671 // Revision 1.16  2014/07/09 11:37:15  abbott
672 // Summary: Removed several fns which are now in FractionFieldBase
673 // Author: JAA
674 //
675 // Revision 1.15  2014/07/08 15:23:16  abbott
676 // Summary: Updated to fit in with new FractionFieldBase
677 // Author: JAA
678 //
679 // Revision 1.14  2014/07/08 13:14:40  abbott
680 // Summary: Removed AsQuotientRing; added new defn of BaseRing
681 // Author: JAA
682 //
683 // Revision 1.13  2014/07/08 08:36:43  abbott
684 // Summary: Removed AsFractionField
685 // Author: JAA
686 //
687 // Revision 1.12  2014/06/14 19:45:07  abbott
688 // Summary: Added new fn CmpAbs for RingElem (via memfn myCmpAbs)
689 // Author: JAA
690 //
691 // Revision 1.11  2014/05/14 15:57:15  bigatti
692 // -- added "using" for clang with superpedantic flag
693 //
694 // Revision 1.10  2014/04/02 10:57:46  abbott
695 // Summary: Revised design of IamIntegralDomain3
696 // Author: JAA
697 //
698 // Revision 1.9  2014/03/27 17:17:31  abbott
699 // Summary: Added new fn IsIntegralDomain3 (and mem fn IamIntegralDomain3)
700 // Author: JAA
701 //
702 // Revision 1.8  2013/05/21 11:32:09  abbott
703 // Replaced mem fns FractionFieldBase::myGetNum (and Den) by FractionFieldBase::myRawNum (and Den).
704 //
705 // Revision 1.7  2013/02/21 14:14:42  abbott
706 // First attempt at implementing PartialRingHom -- some problems remain!!
707 //
708 // Revision 1.6  2012/10/24 13:36:54  abbott
709 // Corrected alignment of a comment.
710 //
711 // Revision 1.5  2012/05/28 10:35:32  abbott
712 // Changed default defn of IsTrueGCDDomain (makes RingQQImpl a bit simpler).
713 //
714 // Revision 1.4  2012/05/28 09:18:21  abbott
715 // Created IntOperations which gathers together all operations on
716 // integers (both big and small).  Many consequential changes.
717 //
718 // Revision 1.3  2012/05/22 10:02:37  abbott
719 // Removed IsGCDDomain; substituted by IsTrueGCDDomain.
720 // Added IsFractionFieldOfGCDDomain.
721 //
722 // Revision 1.2  2012/04/27 15:03:39  abbott
723 // Added mem fn IamFiniteField
724 //
725 // Revision 1.1  2012/02/10 12:16:13  bigatti
726 // -- was RingQ.C
727 //
728 // Revision 1.23  2012/02/10 10:30:03  bigatti
729 // -- changed RingZ.H, RingQ.H --> RingZZ.H, RingQQ.H
730 //
731 // Revision 1.22  2012/02/08 13:45:18  bigatti
732 // -- changed Z,Q --> ZZ,QQ
733 //
734 // Revision 1.21  2011/11/09 14:11:58  bigatti
735 // -- renamed MachineInteger --> MachineInt
736 //
737 // Revision 1.20  2011/09/06 15:28:58  abbott
738 // Changed impl of  "myCmp" so that its return value is in {-1,0,+1}
739 //
740 // Revision 1.19  2011/08/24 10:28:49  bigatti
741 // -- renamed QQ --> BigRat
742 // -- sorted #include
743 //
744 // Revision 1.18  2011/08/14 15:52:16  abbott
745 // Changed ZZ into BigInt (phase 1: just the library sources).
746 //
747 // Revision 1.17  2011/08/03 09:05:44  abbott
748 // Minor change to silence a mistaken compiler warning.
749 //
750 // Revision 1.16  2011/06/23 16:04:47  abbott
751 // Added IamExact mem fn for rings.
752 // Added myRecvTwinFloat mem fn for rings.
753 // Added first imple of RingHom from RingTwinFloat to other rings.
754 //
755 // Revision 1.15  2011/05/19 14:46:07  abbott
756 // Added defn of myIsDouble.
757 //
758 // Revision 1.14  2011/03/10 16:39:34  abbott
759 // Replaced (very many) size_t by long in function interfaces (for rings,
760 // PPMonoids and modules).  Also replaced most size_t inside fn defns.
761 //
762 // Revision 1.13  2010/11/02 15:32:42  bigatti
763 // -- fixed myIsPrintAtom
764 //
765 // Revision 1.12  2010/10/27 20:58:45  abbott
766 // Major reorganization of GlobalManager and GMPAllocator.
767 //
768 // Revision 1.11  2010/09/30 14:42:17  abbott
769 // Changed copyright date.
770 //
771 // Revision 1.10  2010/09/30 14:41:32  abbott
772 // Added new fn to check whether RingQ has ref count greater than 1: this will
773 // happen only if RingQ is referred to by objects other than the GlobalManager.
774 // The fn is called only from the dtor of GlobalManager.
775 //
776 // RingQImpl ctor now increments its ref count at the start: this is necessary
777 // for exception cleanliness (see doc for details).
778 //
779 // Minor changes to MakeUniqueInstanceOfRingQ which must now take RingZ as arg
780 // (since no global RingZ exists when the fn is called during construction of
781 // the GlobalManager).
782 //
783 // Revision 1.9  2009/10/29 18:33:02  abbott
784 // Changed order of include directives (now alphabetical by file name).
785 // Removed some unnecessary std:: prefixes.
786 //
787 // Revision 1.8  2009/10/26 15:40:23  bigatti
788 // -- added CopyFromMPZ in ZZ ctor
789 //
790 // Revision 1.7  2009/07/02 16:32:11  abbott
791 // Consequential changes stemming from new class QQ, and modified interface to the member
792 // function RingBase::myIsRational.  Also some new conversion functions.
793 //
794 // Revision 1.6  2008/12/17 12:11:52  abbott
795 // Changed type from long to MachineInt in operations which use a machine integer
796 // in place of a RingElem.  The change is "superficial" but affects many files.
797 //
798 // Revision 1.5  2008/11/20 10:49:04  abbott
799 // Added definition of myFloor member fn.
800 //
801 // Revision 1.4  2007/10/30 17:14:07  abbott
802 // Changed licence from GPL-2 only to GPL-3 or later.
803 // New version for such an important change.
804 //
805 // Revision 1.3  2007/05/22 22:45:14  abbott
806 // Changed fn name IsUnit to IsInvertible.
807 //
808 // Revision 1.2  2007/03/28 10:06:13  abbott
809 // Now gives error when you use RingZ() or RingQ() without creating GlobalManager.
810 //
811 // Revision 1.1.1.1  2007/03/09 15:16:11  abbott
812 // Imported files
813 //
814 // Revision 1.13  2007/03/05 21:25:57  cocoa
815 // Forgot to check these in a few minutes ago.
816 //
817 // Revision 1.12  2007/03/02 10:47:53  cocoa
818 // First stage of RingZ modifications -- tests do not compile currently, Anna will fix this.
819 //
820 // Revision 1.11  2007/02/26 15:00:54  bigatti
821 // -- added placeholders for new syntax based on unique Z implementation
822 //
823 // Revision 1.10  2007/01/17 12:32:39  cocoa
824 // Changed a few more "raw" variable names so that the code compiles fine
825 // also when CoCoA_DEBUG is set.
826 //
827 // Revision 1.9  2007/01/15 16:08:26  cocoa
828 // -- added prefix "raw" to RawPtr arguments names
829 // -- changed rhs into rawx, n, or N
830 //
831 // Revision 1.8  2007/01/13 14:14:34  cocoa
832 // Overhaul of RingHom code: it nows uses SmartPtrIRC, and printing is more logical.
833 // Have not yet updated the documentation.
834 //
835 // Revision 1.7  2006/11/27 14:26:24  cocoa
836 // -- reorganised #include files
837 //
838 // Revision 1.6  2006/11/08 16:21:59  cocoa
839 // Structural cleaning of RingHom; many consequential changes.
840 //
841 // Revision 1.5  2006/11/03 14:01:46  cocoa
842 // -- changed: reference counting in ring, PPMonoids and OrdvArith now
843 //    uses SmartPtrIRC
844 //
845 // Revision 1.4  2006/11/02 13:25:44  cocoa
846 // Simplification of header files: the OpenMath classes have been renamed.
847 // Many minor consequential changes.
848 //
849 // Revision 1.3  2006/10/16 23:18:59  cocoa
850 // Corrected use of std::swap and various special swap functions.
851 // Improved myApply memfn for homs of RingDistrMPolyInlPP.
852 //
853 // Revision 1.2  2006/10/06 14:04:14  cocoa
854 // Corrected position of #ifndef in header files.
855 // Separated CoCoA_ASSERT into assert.H from config.H;
856 // many minor consequential changes (have to #include assert.H).
857 // A little tidying of #include directives (esp. in Max's code).
858 //
859 // Revision 1.1.1.1  2006/05/30 11:39:37  cocoa
860 // Imported files
861 //
862 // Revision 1.7  2006/05/29 16:22:37  cocoa
863 // Third time lucky???
864 // Added myIsInteger member function to all rings (NYI for RingFloat).
865 //
866 // Revision 1.6  2006/05/12 16:10:58  cocoa
867 // Added OpenMathFwd.H, and tidied OpenMath.H.
868 // Many consequential but trivial changes.
869 //
870 // Revision 1.5  2006/04/21 15:01:36  cocoa
871 // Changed default implementation of RingBase::myGcd -- it now gives a SERIOUS
872 // error.  All fields must now handle a call to gcd explicitly: they can use
873 // the new myGcdInField function.  It's now cleaner than it was.
874 //
875 // Revision 1.4  2006/03/15 18:09:31  cocoa
876 // Changed names of member functions which print out their object
877 // into myOutputSelf -- hope this will appease the Intel C++ compiler.
878 //
879 // Revision 1.3  2006/03/14 15:01:49  cocoa
880 // Improved the implementation of ring member fns for computing powers.
881 // Should keep Intel C++ compiler quieter too.
882 //
883 // Revision 1.2  2006/03/12 21:28:33  cocoa
884 // Major check in after many changes
885 //
886 // Revision 1.1.1.1  2005/10/17 10:46:54  cocoa
887 // Imported files
888 //
889 // Revision 1.3  2005/09/22 18:04:17  cocoa
890 // It compiles; the tests run OK.  The examples compile.
891 // No documentation -- the mindless eurocrats have rendered
892 // me mindless too.
893 //
894 // Revision 1.2  2005/06/22 14:42:16  cocoa
895 // Renamed MemPool data member to myMemMgr
896 // (seems more sensible than myMemory).
897 //
898 // Revision 1.1.1.1  2005/05/03 15:47:31  cocoa
899 // Imported files
900 //
901 // Revision 1.4  2005/04/20 15:40:48  cocoa
902 // Major change: modified the standard way errors are to be signalled
903 // (now via a macro which records filename and line number).  Updated
904 // documentation in error.txt accordingly.
905 //
906 // Improved the documentation in matrix.txt (still more work to be done).
907 //
908 // Revision 1.3  2005/04/19 14:06:03  cocoa
909 // Added GPL and GFDL licence stuff.
910 //
911 // Revision 1.2  2005/02/11 14:15:20  cocoa
912 // New style ring elements and references to ring elements;
913 // I hope I have finally got it right!
914 //
915 // Revision 1.1.1.1  2005/01/27 15:12:13  cocoa
916 // Imported files
917 //
918 // Revision 1.14  2004/11/18 18:33:41  cocoa
919 // Now every ring know its own "one" element (as well as "zero").
920 // Several consequential changes.
921 //
922 // Revision 1.13  2004/11/12 15:49:29  cocoa
923 // Tidying prior to 0.90 release.
924 // (a) documentation improved (or marked as poor)
925 // (b) sundry minor improvements to the code
926 //
927 // Revision 1.12  2004/11/11 11:56:09  cocoa
928 // (1) Tidied makefiles, and introduced common.mki
929 // (2) Improved several tests, and cleaned them so that they
930 //     handle sanely any otherwise unhandled exceptions.
931 //
932 // Revision 1.11  2004/11/05 15:34:33  cocoa
933 // Consequential change following from the renaming of
934 // FieldIdealImpl and the introduction of the new pseudo-ctor.
935 //
936 // Revision 1.10  2004/11/04 18:47:43  cocoa
937 // (1) Ring member functions which previously expected mpz_t args
938 //     now expect ZZ args.  Numerous minor consequential changes.
939 // (2) Renamed function which gives access to the mpz_t value inside
940 //     a ZZ object: previously was raw(...), now is mpzref(...).
941 //     Plenty of calls had to be altered.
942 //
943 // Revision 1.9  2004/07/27 16:03:39  cocoa
944 // Added IsCommutative test and IamCommutative member function
945 // to all rings.  Tidied geobuckets a little.
946 //
947 // Revision 1.8  2004/07/14 16:40:42  cocoa
948 // Separated RingFpLog from its implementation which now resides in
949 // a new class: SmallFpLogImpl.  This is analogous to the change made
950 // to RingFp yesterday.
951 //
952 // Some tidying and other sundry minor changes.
953 //
954 // Revision 1.7  2004/05/24 15:52:13  cocoa
955 // Major update:
956 //   new error mechanism
957 //   many fixes
958 //   RingHoms almost work now
959 //   RingFloat much improved
960 //
961 // Revision 1.6  2004/04/08 15:33:34  cocoa
962 // Added function IsInteger, and the related RingBase::myIsInteger
963 // virtual function, plus all necessary implementations.
964 //
965 // Revision 1.5  2004/03/20 17:46:10  cocoa
966 // Check in prior to departure to RWCA
967 //
968 // Revision 1.4  2004/02/03 16:16:20  cocoa
969 // Removed pointless IamGCDDomain functions from several concrete rings.
970 // Added IamOrderedDomain functions where appropriate.
971 // Tidied ctors for the small finite fields.
972 //
973 // Revision 1.3  2004/01/30 14:07:10  cocoa
974 // Tidied RingRawValue union: now it contains just two fields,
975 // and has no need of forward declarations of types used internally
976 // by the concrete rings -- it uses explicitly a void* instead.
977 //
978 // I have tidied the "import" functions used by most concrete rings.
979 //
980 // I have moved the choice of representation type for RingFp and RingFpLog
981 // into a typedef in config.H -- this is to recognise that different
982 // choices may work best on different platforms.
983 //
984 // Revision 1.2  2003/10/17 10:51:06  cocoa
985 // Major cleaning, and new naming convention.
986 //
987 // Revision 1.1  2003/10/09 12:48:17  cocoa
988 // New coding convention for rings.
989 //
990 //
991