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