1 // Copyright (c) 2015 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/RingFqVec.H" 19 20 #include "CoCoA/BigIntOps.H" 21 #include "CoCoA/BigRat.H" 22 #include "CoCoA/FieldIdeal.H" 23 #include "CoCoA/NumTheory-prime.H" 24 #include "CoCoA/OpenMath.H" 25 #include "CoCoA/QuotientRing.H" 26 #include "CoCoA/RingFp.H" 27 #include "CoCoA/RingHom.H" 28 #include "CoCoA/SmallFpImpl.H" 29 #include "CoCoA/SmallFqUtils.H" 30 #include "CoCoA/SmallFqVecImpl.H" 31 #include "CoCoA/SparsePolyIter.H" // for myReduction 32 #include "CoCoA/SparsePolyOps-RingElem.H" 33 //#include "CoCoA/SparsePolyRing.H" // from SparsePolyOps-RingElem.H 34 #include "CoCoA/error.H" 35 36 #include <iostream> 37 using std::ostream; 38 39 //#include <vector> 40 using std::vector; 41 42 #include <memory> 43 using std::unique_ptr; 44 45 namespace CoCoA 46 { 47 class RingFqVecImpl: public QuotientRingBase 48 { 49 private: // data members 50 typedef SmallFpImpl::value FpElem; 51 const long myDeg; 52 const FFqImpl_vec myImpl; 53 // const FpElem myModulus; 54 // const SmallFpImpl myImpl; 55 mutable MemPool myMemMgr; // MemPool must come *BEFORE* myZeroPtr and myOnePtr 56 unique_ptr<RingElem> myZeroPtr; ///< Every ring stores its own zero. 57 unique_ptr<RingElem> myOnePtr; ///< Every ring stores its own one. 58 unique_ptr<RingElem> myGenPtr; ///< Every ring stores its own one. 59 60 private: // auxiliary functions 61 static FpElem PrincipalGen(const ideal& I); // used for arg checking in ctor 62 static FpElem* import(RingElemRawPtr rawx); 63 static const FpElem* import(RingElemConstRawPtr rawx); 64 65 private: 66 explicit RingFqVecImpl(long p, int d); // called only by NewRingFqVec 67 RingFqVecImpl(const ideal& I); 68 ~RingFqVecImpl(); 69 friend ring NewRingFqVec(const MachineInt& p, const MachineInt& d); // create field of size p^d 70 friend ring NewRingFqVec(const BigInt& p, const MachineInt& d); // create field of size p^d 71 friend ring NewRingFqVec(const MachineInt& p, const BigInt& d); // create field of size p^d 72 friend ring NewRingFqVec(const BigInt& p, const BigInt& d); // create field of size p^d 73 private: 74 RingFqVecImpl(const RingFqVecImpl&); ///< NEVER DEFINED -- disallow copy construction 75 RingFqVecImpl& operator=(const RingFqVecImpl&); ///< NEVER DEFINED -- disallow assignment 76 public: myGenerator()77 RingElem myGenerator() const { return *myGenPtr; } 78 // functions required by every 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 ConstRefRingElem myZero() const; 87 virtual ConstRefRingElem myOne() const; 88 using RingBase::myNew; // disable warnings of overloading 89 using RingBase::myAssign; // disable warnings of overloading 90 virtual RingElemRawPtr myNew() const; 91 virtual RingElemRawPtr myNew(const MachineInt& n) const; 92 virtual RingElemRawPtr myNew(const BigInt& N) const; 93 virtual RingElemRawPtr myNew(ConstRawPtr rawt) const; 94 virtual void myDelete(RawPtr rawx) const; // destroys x (incl all resources) 95 virtual void mySwap(RawPtr rawx, RawPtr rawy) const; // swap(x, y) 96 virtual void myAssign(RawPtr rawlhs, ConstRawPtr rawx) const; // lhs = x 97 virtual void myAssign(RawPtr rawlhs, const MachineInt& n) const; // lhs = n 98 virtual void myAssign(RawPtr rawlhs, const BigInt& N) const; // lhs = N 99 virtual void myAssignZero(RawPtr rawlhs) const; // lhs = 0 100 virtual void myRecvTwinFloat(RawPtr rawlhs, ConstRawPtr rawx) const; 101 virtual void myNegate(RawPtr rawlhs, ConstRawPtr rawx) const; // lhs = -x 102 virtual void myAdd(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const; // lhs = x+y 103 virtual void mySub(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const; // lhs = x-y 104 virtual void myMul(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const; // lhs = x*y 105 virtual void myDiv(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const; // lhs = x/y 106 virtual bool myIsDivisible(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const;// lhs = x/y, if divisible 107 virtual bool myIsInvertible(ConstRawPtr rawx) const; // true iff x is invertible 108 virtual void myGcd(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const; // lhs = gcd(x,y) in a field 109 virtual void myPowerSmallExp(RawPtr rawlhs, ConstRawPtr rawx, long n) const; // lhs = x^n, n>1, x not -1,0,1 110 virtual void myPowerBigExp(RawPtr rawlhs, ConstRawPtr rawx, const BigInt& N) const; // lhs = x^N, N big, x not -1,0,1 111 virtual void myOutput(std::ostream& out, ConstRawPtr rawx) const; // out << x 112 virtual bool myIsPrintAtom(ConstRawPtr rawx) const; 113 virtual bool myIsPrintedWithMinus(ConstRawPtr rawx) const; 114 virtual void myOutputSelf(std::ostream& out) const; // out << R 115 virtual void myOutputSelf(OpenMathOutput& OMOut) const; // OMOut << R 116 virtual void myOutput(OpenMathOutput& OMOut, ConstRawPtr rawx) const; // OMOut << x 117 virtual bool myIsZero(ConstRawPtr rawx) const; // x == 0 118 virtual bool myIsOne(ConstRawPtr rawx) const; // x == 1 119 virtual bool myIsMinusOne(ConstRawPtr rawx) const; // x == -1 120 virtual bool myIsInteger(BigInt& N, ConstRawPtr rawx) const; // always true 121 virtual bool myIsRational(BigRat& Q, ConstRawPtr rawx) const; // true iff x is rational 122 virtual bool myIsDouble(double& d, ConstRawPtr rawx) const; // false iff x overflows 123 // virtual bool myIsZeroAddMul(RawPtr rawlhs, ConstRawPtr rawy, ConstRawPtr rawz) const;// lhs += y*z, result says whether lhs == 0. 124 // virtual bool myIsZeroAddMul(RawPtr rawlhs, RawPtr /*rawtmp*/, ConstRawPtr rawy, ConstRawPtr rawz) const;// lhs += y*z, result says whether lhs == 0. 125 virtual bool myIsEqual(ConstRawPtr rawx, ConstRawPtr rawy) const; // x == y 126 virtual RingElem mySymbolValue(const symbol& /*sym*/) const; 127 virtual ideal myIdealCtor(const std::vector<RingElem>& gens) const; 128 129 virtual RingHom myCompose(const RingHom& phi, const RingHom& theta) const; // phi(theta(...)) 130 131 virtual bool myImageLiesInSubfield(const RingHom& phi) const; 132 133 // functions required for a QuotientRing 134 virtual RingElem myCanonicalRepr(ConstRawPtr rawx) const; // result is element of myReprRing 135 virtual void myReduction(RawPtr rawimage, ConstRawPtr rawarg) const; 136 virtual RingHom myInducedHomCtor(const RingHom& InducingHom) const; 137 138 139 private: 140 class InducedHomImpl: public RingHomBase 141 { 142 public: 143 InducedHomImpl(const QuotientRing& domain, const RingHom& InducingHom); 144 virtual void myApply(RingElemRawPtr rawimage, RingElemConstRawPtr rawarg) const; IamPartial()145 virtual bool IamPartial() const { return false; } 146 private: 147 RingHom myInducingHom; 148 }; 149 150 }; 151 import(RingElemRawPtr rawx)152 inline RingFqVecImpl::FpElem* RingFqVecImpl::import(RingElemRawPtr rawx) 153 { 154 return static_cast<FpElem*>(rawx.myRawPtr()); 155 } 156 import(RingElemConstRawPtr rawx)157 inline const RingFqVecImpl::FpElem* RingFqVecImpl::import(RingElemConstRawPtr rawx) 158 { 159 return static_cast<const FpElem*>(rawx.myRawPtr()); 160 } 161 162 163 // // Returns generator of I as a FpElem; returns 0 if value is too large to fit. 164 // RingFqVecImpl::FpElem RingFqVecImpl::PrincipalGen(const ideal& I) 165 // { 166 // if (IsZero(I)) return 0; 167 // const BigInt GenI = ConvertTo<BigInt>(TidyGens(I)[0]); 168 // FpElem p; 169 // if (!IsConvertible(p, GenI)) // check that the value of the principal generator will fit 170 // return 0; 171 // return p; 172 // } 173 174 175 RingFqVecImpl(const ideal & I)176 RingFqVecImpl::RingFqVecImpl(const ideal& I): 177 QuotientRingBase(RingOf(I), I), 178 myDeg(deg(gens(I)[0])), 179 myImpl(I), 180 myMemMgr(myDeg*SmallFpImpl::ourDatumSize, "RingFqVecImpl.myMemMgr"), 181 myZeroPtr(), 182 myOnePtr(), 183 myGenPtr() 184 { 185 myRefCountInc(); // this is needed for exception cleanliness, in case one of the lines below throws 186 myZeroPtr.reset(new RingElem(ring(this))); 187 myOnePtr.reset(new RingElem(ring(this), 1)); 188 myGenPtr.reset(new RingElem(ring(this))); 189 myImpl.myGen(import(raw(*myGenPtr))); 190 myRefCountZero(); 191 } 192 193 ~RingFqVecImpl()194 RingFqVecImpl::~RingFqVecImpl() 195 {} 196 197 myCharacteristic(BigInt & p)198 void RingFqVecImpl::myCharacteristic(BigInt& p) const 199 { 200 p = myImpl.myModulus(); 201 } 202 203 myLogCardinality()204 long RingFqVecImpl::myLogCardinality() const 205 { 206 return myImpl.myExtnDeg(); 207 } 208 209 IamCommutative()210 bool RingFqVecImpl::IamCommutative() const 211 { 212 return true; 213 } 214 215 IamIntegralDomain3(bool)216 bool3 RingFqVecImpl::IamIntegralDomain3(bool) const 217 { 218 return true3; 219 } 220 221 IamField()222 bool RingFqVecImpl::IamField() const 223 { 224 return true; 225 } 226 227 IamFiniteField()228 bool RingFqVecImpl::IamFiniteField() const 229 { 230 return true; 231 } 232 233 IamExact()234 bool RingFqVecImpl::IamExact() const 235 { 236 return true; 237 } 238 239 myZero()240 ConstRefRingElem RingFqVecImpl::myZero() const 241 { 242 return *myZeroPtr; 243 } 244 245 myOne()246 ConstRefRingElem RingFqVecImpl::myOne() const 247 { 248 return *myOnePtr; 249 } 250 251 myNew()252 RingElemRawPtr RingFqVecImpl::myNew() const 253 { 254 FpElem* ans = static_cast<FpElem*>(myMemMgr.alloc()); 255 for (int i=0;i<myDeg;++i) ans[i]=zero(SmallFp); 256 return RingElemRawPtr(ans); 257 } 258 259 myNew(const MachineInt & n)260 RingElemRawPtr RingFqVecImpl::myNew(const MachineInt& n) const 261 { 262 FpElem* ans = static_cast<FpElem*>(myMemMgr.alloc()); 263 ans[0] = myImpl.myFpArith().myReduce(n); 264 for (int i=1;i<myDeg;++i) ans[i]=zero(SmallFp); 265 return RingElemRawPtr(ans); 266 } 267 268 myNew(const BigInt & N)269 RingElemRawPtr RingFqVecImpl::myNew(const BigInt& N) const 270 { 271 FpElem* ans = static_cast<FpElem*>(myMemMgr.alloc()); 272 ans[0] = myImpl.myFpArith().myReduce(N); 273 for (int i=1;i<myDeg;++i) ans[i]=zero(SmallFp); 274 return RingElemRawPtr(ans); 275 } 276 277 myNew(ConstRawPtr rawy)278 RingElemRawPtr RingFqVecImpl::myNew(ConstRawPtr rawy) const 279 { 280 FpElem* ans = static_cast<FpElem*>(myMemMgr.alloc()); 281 for (int i=0;i<myDeg;++i) ans[i]=import(rawy)[i];// *ans = import(rawy); 282 return RingElemRawPtr(ans); 283 } 284 285 myDelete(RawPtr rawx)286 void RingFqVecImpl::myDelete(RawPtr rawx) const 287 { 288 myMemMgr.free(rawx.myRawPtr()); 289 } 290 291 mySwap(RawPtr rawx,RawPtr rawy)292 void RingFqVecImpl::mySwap(RawPtr rawx, RawPtr rawy) const 293 { 294 for (int i=0;i<myDeg;++i) 295 std::swap(import(rawx)[i], import(rawy)[i]); 296 } 297 298 myAssign(RawPtr rawlhs,ConstRawPtr rawx)299 void RingFqVecImpl::myAssign(RawPtr rawlhs, ConstRawPtr rawx) const 300 { 301 for (int i=0;i<myDeg;++i) 302 import(rawlhs)[i] = import(rawx)[i]; 303 } 304 305 myAssign(RawPtr rawlhs,const MachineInt & n)306 void RingFqVecImpl::myAssign(RawPtr rawlhs, const MachineInt& n) const 307 { 308 import(rawlhs)[0] = myImpl.myFpArith().myReduce(n); 309 for (int i=1;i<myDeg;++i) 310 import(rawlhs)[i] = zero(SmallFp); 311 } 312 313 myAssign(RawPtr rawlhs,const BigInt & N)314 void RingFqVecImpl::myAssign(RawPtr rawlhs, const BigInt& N) const 315 { 316 import(rawlhs)[0] = myImpl.myFpArith().myReduce(N); 317 for (int i=1;i<myDeg;++i) 318 import(rawlhs)[i] = zero(SmallFp); 319 } 320 321 myAssignZero(RawPtr rawlhs)322 void RingFqVecImpl::myAssignZero(RawPtr rawlhs) const 323 { 324 for (int i=0;i<myDeg;++i) 325 import(rawlhs)[i] = zero(SmallFp); 326 } 327 328 myRecvTwinFloat(RawPtr,ConstRawPtr)329 void RingFqVecImpl::myRecvTwinFloat(RawPtr /*rawlhs*/, ConstRawPtr /*rawx*/) const 330 { 331 CoCoA_THROW_ERROR(ERR::ShouldNeverGetHere, "RingFqVecImpl::myRecvTwinFloat"); 332 } 333 334 myNegate(RawPtr rawlhs,ConstRawPtr rawx)335 void RingFqVecImpl::myNegate(RawPtr rawlhs, ConstRawPtr rawx) const 336 { 337 for (int i=0;i<myDeg;++i) 338 import(rawlhs)[i] = myImpl.myFpArith().myNegate(import(rawx)[i]); 339 } 340 341 myAdd(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)342 void RingFqVecImpl::myAdd(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const 343 { 344 myImpl.myAdd(import(rawlhs), import(rawx), import(rawy)); 345 } 346 347 mySub(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)348 void RingFqVecImpl::mySub(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const 349 { 350 myImpl.mySub(import(rawlhs), import(rawx), import(rawy)); 351 } 352 353 myMul(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)354 void RingFqVecImpl::myMul(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const 355 { 356 myImpl.myMul(import(rawlhs), import(rawx), import(rawy)); 357 } 358 359 myDiv(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)360 void RingFqVecImpl::myDiv(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const 361 { 362 CoCoA_ASSERT(!myIsZero(rawy)); 363 myImpl.myDiv(import(rawlhs), import(rawx), import(rawy)); 364 } 365 366 myIsDivisible(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)367 bool RingFqVecImpl::myIsDivisible(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const 368 { 369 if (import(rawy) == 0) return false; 370 myImpl.myDiv(import(rawlhs), import(rawx), import(rawy)); 371 return true; 372 } 373 374 myIsInvertible(ConstRawPtr rawx)375 bool RingFqVecImpl::myIsInvertible(ConstRawPtr rawx) const 376 { 377 return !myIsZero(rawx); 378 } 379 380 myGcd(RawPtr rawlhs,ConstRawPtr rawx,ConstRawPtr rawy)381 void RingFqVecImpl::myGcd(RawPtr rawlhs, ConstRawPtr rawx, ConstRawPtr rawy) const 382 { 383 myGcdInField(rawlhs, rawx, rawy); 384 } 385 386 myPowerSmallExp(RawPtr rawlhs,ConstRawPtr rawx,long n)387 void RingFqVecImpl::myPowerSmallExp(RawPtr rawlhs, ConstRawPtr rawx, long n) const // assumes n > 1 388 { 389 // Assert that we have a genuinely non-trivial case. 390 CoCoA_ASSERT(n > 1); 391 CoCoA_ASSERT(!myIsZero(rawx) && !myIsOne(rawx) && !myIsMinusOne(rawx)); 392 myImpl.myPower(import(rawlhs), import(rawx), n); 393 } 394 myPowerBigExp(RawPtr rawlhs,ConstRawPtr rawx,const BigInt & N)395 void RingFqVecImpl::myPowerBigExp(RawPtr rawlhs, ConstRawPtr rawx, const BigInt& N) const 396 { 397 // Assert that we have a genuinely non-trivial case. 398 CoCoA_ASSERT(N > 1); 399 CoCoA_ASSERT(!myIsZero(rawx) && !myIsOne(rawx) && !myIsMinusOne(rawx)); 400 // Use Fermat's Little Theorem to reduce exponent... 401 const long card = SmallPower(myImpl.myModulus(), myImpl.myExtnDeg()); 402 myImpl.myPower(import(rawlhs), import(rawx), N%(card-1)); 403 } 404 405 myOutput(ostream & out,ConstRawPtr rawx)406 void RingFqVecImpl::myOutput(ostream& out, ConstRawPtr rawx) const 407 { 408 if (!out) return; // short-cut for bad ostreams 409 410 const SmallFpImpl& ModP(myImpl.myFpArith()); 411 const SmallFpImpl::value* v = import(rawx); 412 out << "[" << ModP.myExport(v[0]); 413 for (int i=1; i < myDeg; ++i) 414 out << ", " << ModP.myExport(v[i]); 415 out <<"]"; 416 } 417 418 myIsPrintAtom(ConstRawPtr rawx)419 bool RingFqVecImpl::myIsPrintAtom(ConstRawPtr rawx) const 420 { 421 return false; ///??? BUG BUG BUG ???probably OK if image of an int? 422 // return myImpl.myExport(import(rawx)) >= 0; 423 } 424 425 myIsPrintedWithMinus(ConstRawPtr rawx)426 bool RingFqVecImpl::myIsPrintedWithMinus(ConstRawPtr rawx) const 427 { 428 return false; ///??? BUG BUG BUG STOPGAP impl, see comment in isprintatom 429 // return myImpl.myExport(import(rawx)) < 0; 430 } 431 432 myOutputSelf(ostream & out)433 void RingFqVecImpl::myOutputSelf(ostream& out) const 434 { 435 if (!out) return; // short-cut for bad ostreams 436 // out << "FFp(" << myModulus << ")"; 437 out << "RingWithID(" << myID << ",\"FFqVec(p=" << myImpl.myModulus() << ", deg=" << myDeg << ")\")"; 438 } 439 440 myOutputSelf(OpenMathOutput & OMOut)441 void RingFqVecImpl::myOutputSelf(OpenMathOutput& OMOut) const 442 { 443 // OMOut->mySendApplyStart(); 444 // OMOut << OpenMathSymbol("setname2", "GFp"); 445 // OMOut << myModulus; 446 // OMOut->mySendApplyEnd(); 447 } 448 449 myOutput(OpenMathOutput & OMOut,ConstRawPtr rawx)450 void RingFqVecImpl::myOutput(OpenMathOutput& OMOut, ConstRawPtr rawx) const 451 { 452 CoCoA_THROW_ERROR(ERR::NYI, "RingFqVecImpl::myOutput"); 453 OMOut << 0; //???myImpl.myExport(import(rawx)); 454 } 455 456 myIsZero(ConstRawPtr rawx)457 bool RingFqVecImpl::myIsZero(ConstRawPtr rawx) const 458 { 459 for (int i=0;i<myDeg;++i) 460 if (!IsZero(import(rawx)[i])) return false; 461 return true; 462 } 463 464 myIsOne(ConstRawPtr rawx)465 bool RingFqVecImpl::myIsOne(ConstRawPtr rawx) const 466 { 467 for (int i=1;i<myDeg;++i) 468 if (!IsZero(import(rawx)[i])) return false; 469 return IsOne(import(rawx)[0]); 470 } 471 472 myIsMinusOne(ConstRawPtr rawx)473 bool RingFqVecImpl::myIsMinusOne(ConstRawPtr rawx) const 474 { 475 for (int i=1;i<myDeg;++i) 476 if (!IsZero(import(rawx)[i])) return false; 477 return import(rawx)[0] == myImpl.myFpArith().myReduce(-1); 478 } 479 480 myIsInteger(BigInt & N,ConstRawPtr rawx)481 bool RingFqVecImpl::myIsInteger(BigInt& N, ConstRawPtr rawx) const 482 { 483 for (int i=1;i<myDeg;++i) 484 if (!IsZero(import(rawx)[i])) return false; 485 N = myImpl.myFpArith().myExport(import(rawx)[0]); 486 return true; 487 } 488 489 myIsRational(BigRat & Q,ConstRawPtr rawx)490 bool RingFqVecImpl::myIsRational(BigRat& Q, ConstRawPtr rawx) const 491 { 492 for (int i=1;i<myDeg;++i) 493 if (!IsZero(import(rawx)[i])) return false; 494 Q = myImpl.myFpArith().myExport(import(rawx)[0]); 495 return true; 496 } 497 498 myIsDouble(double & d,ConstRawPtr rawx)499 bool RingFqVecImpl::myIsDouble(double& d, ConstRawPtr rawx) const 500 { 501 for (int i=1;i<myDeg;++i) 502 if (!IsZero(import(rawx)[i])) return false; 503 d = myImpl.myFpArith().myExport(import(rawx)[0]); 504 return true; 505 } 506 507 508 // bool RingFqVecImpl::myIsZeroAddMul(RawPtr rawlhs, ConstRawPtr rawfact1, ConstRawPtr rawfact2) const 509 // { 510 // return myImpl.myIsZeroAddMul(import(rawlhs), import(rawfact1), import(rawfact2)); 511 // } 512 513 514 // bool RingFqVecImpl::myIsZeroAddMul(RawPtr rawlhs, RawPtr /*rawtmp*/, ConstRawPtr rawfact1, ConstRawPtr rawfact2) const 515 // { // same as above: just to avoid calling RingBase::myIsZeroAddMul with 4 args 516 // return myImpl.myIsZeroAddMul(import(rawlhs), import(rawfact1), import(rawfact2)); 517 // } 518 519 myIsEqual(ConstRawPtr rawx,ConstRawPtr rawy)520 bool RingFqVecImpl::myIsEqual(ConstRawPtr rawx, ConstRawPtr rawy) const 521 { 522 for (int i=0;i<myDeg;++i) 523 if (import(rawx)[i] != import(rawy)[i]) return false; 524 return true; 525 } 526 527 mySymbolValue(const symbol &)528 RingElem RingFqVecImpl::mySymbolValue(const symbol& /*sym*/) const {CoCoA_THROW_ERROR("This ring has no symbols", "RingFqVecImpl::mySymbolValue"); return myZero();} 529 530 myIdealCtor(const std::vector<RingElem> & gens)531 ideal RingFqVecImpl::myIdealCtor(const std::vector<RingElem>& gens) const 532 { 533 return NewFieldIdeal(ring(this), gens); 534 } 535 536 myCompose(const RingHom & phi,const RingHom & theta)537 RingHom RingFqVecImpl::myCompose(const RingHom& phi, const RingHom& theta) const 538 { 539 // No need to check compatibility -- it was checked when theta and phi were built 540 //??? return RingHom(new InducedHomImpl(QuotientRing(this), phi(theta(myQuotientingHomCtor())))); 541 return myCompose(theta,phi);// BUG BUG BUG just to keep compiler quiet 542 } 543 544 myImageLiesInSubfield(const RingHom & phi)545 bool RingFqVecImpl::myImageLiesInSubfield(const RingHom& phi) const 546 { 547 (void)(phi); // to avoid compiler warning about unused parameter 548 CoCoA_ASSERT(codomain(phi) == ring(this)); 549 return true; 550 } 551 552 553 myCanonicalRepr(ConstRawPtr rawx)554 RingElem RingFqVecImpl::myCanonicalRepr(ConstRawPtr rawx) const 555 { 556 const RingElemAlias x = indet(myBaseRingValue, 0); 557 const vector<long> c = myImpl.myExport(import(rawx)); 558 RingElem ans = zero(myBaseRingValue); 559 for (int i=0; i < myDeg; ++i) 560 ans += c[i]*power(x,i); 561 return ans; 562 } 563 564 myReduction(RawPtr rawimage,ConstRawPtr rawarg)565 void RingFqVecImpl::myReduction(RawPtr rawimage, ConstRawPtr rawarg) const 566 { 567 // Reduce univariate poly mod generator of ideal 568 // convert to vector of coeffs 569 RingElemAlias x(myBaseRingValue, rawarg); 570 RingElem rem = NR(x, gens(myDefiningIdeal)); 571 myAssignZero(rawimage); 572 for (SparsePolyIter it = BeginIter(rem); !IsEnded(it); ++it) 573 { 574 BigInt c; IsInteger(c, coeff(it)); 575 import(rawimage)[deg(PP(it))] = myImpl.myFpArith().myReduce(c); 576 } 577 } 578 579 myInducedHomCtor(const RingHom & InducingHom)580 RingHom RingFqVecImpl::myInducedHomCtor(const RingHom& InducingHom) const 581 { 582 // Compatibility has already been checked (see InducedHom in QuotientRing.C) 583 //??? CoCoA_ASSERT(IsZero(InducingHom(myModulus))); 584 return RingHom(new InducedHomImpl(QuotientRing(this), InducingHom)); 585 } 586 587 InducedHomImpl(const QuotientRing & domain,const RingHom & InducingHom)588 RingFqVecImpl::InducedHomImpl::InducedHomImpl(const QuotientRing& domain, const RingHom& InducingHom): 589 RingHomBase(domain, codomain(InducingHom)), 590 myInducingHom(InducingHom) 591 { 592 CoCoA_ASSERT(IsInKer(DefiningIdeal(domain), InducingHom)); // actually already checked in pseudo-ctor InducedHom (in QuotientRing.C:875) 593 } 594 myApply(RingElemRawPtr rawimage,RingElemConstRawPtr rawarg)595 void RingFqVecImpl::InducedHomImpl::myApply(RingElemRawPtr rawimage, RingElemConstRawPtr rawarg) const 596 { 597 myCodomain->myAssign(rawimage, raw(myInducingHom(QuotientRing(myDomain)->myCanonicalRepr(rawarg)))); 598 } 599 600 NewRingFqVec(const MachineInt & p,const MachineInt & d)601 ring NewRingFqVec(const MachineInt& p, const MachineInt& d) 602 { 603 if (IsNegative(p) || !IsPrime(p)) CoCoA_THROW_ERROR(ERR::BadSmallFpChar, "NewRingFq"); 604 if (IsNegative(d) || AsSignedLong(d) < 2) CoCoA_THROW_ERROR(ERR::BadArg, "NewRingFq"); 605 const long P = AsSignedLong(p); 606 const long deg = AsSignedLong(d); 607 ring Fpx = NewPolyRing(NewRingFp(P), NewSymbols(1)); 608 std::vector<SmallFpImpl::value> v = FindGroupGenerator(P,deg); 609 RingElem MinPoly = VectorToPoly(Fpx, v); 610 // RingElem MinPoly(Fpx); 611 // RingElem x = indet(Fpx,0); 612 // for (int i=0; i <= deg; ++i) MinPoly += v[i] * power(x,i); 613 ideal I(MinPoly); 614 return ring(new RingFqVecImpl(I)); 615 } 616 NewRingFqVec(const BigInt & p,const MachineInt & d)617 ring NewRingFqVec(const BigInt& p, const MachineInt& d) 618 { 619 return NewRingFqVec(ConvertTo<long>(p), d); 620 } NewRingFqVec(const MachineInt & p,const BigInt & d)621 ring NewRingFqVec(const MachineInt& p, const BigInt& d) 622 { 623 return NewRingFqVec(p, ConvertTo<long>(d)); 624 } NewRingFqVec(const BigInt & p,const BigInt & d)625 ring NewRingFqVec(const BigInt& p, const BigInt& d) 626 { 627 return NewRingFqVec(ConvertTo<long>(p), ConvertTo<long>(d)); 628 } 629 630 631 } // end of namespace CoCoA 632 633 634 // RCS header/log in the next few lines 635 // $Header: /Volumes/Home_1/cocoa/cvs-repository/CoCoALib-0.99/src/AlgebraicCore/RingFqVec.C,v 1.13 2020/06/17 15:49:26 abbott Exp $ 636 // $Log: RingFqVec.C,v $ 637 // Revision 1.13 2020/06/17 15:49:26 abbott 638 // Summary: Changed CoCoA_ERROR into CoCoA_THROW_ERROR 639 // 640 // Revision 1.12 2020/02/11 16:56:41 abbott 641 // Summary: Corrected last update (see redmine 969) 642 // 643 // Revision 1.11 2020/02/11 16:12:19 abbott 644 // Summary: Added some checks for bad ostream (even to mem fns myOutput); see redmine 969 645 // 646 // Revision 1.10 2019/03/04 10:58:38 abbott 647 // Summary: Changed auto_ptr into unique_ptr 648 // 649 // Revision 1.9 2018/09/28 15:54:04 abbott 650 // Summary: Removed pseudo-ctors NewPolyRing which took just num of indets; now must specify their names 651 // 652 // Revision 1.8 2018/05/18 16:42:11 bigatti 653 // -- added include SparsePolyOps-RingElem.H 654 // 655 // Revision 1.7 2018/05/18 12:22:30 bigatti 656 // -- renamed IntOperations --> BigIntOps 657 // 658 // Revision 1.6 2018/05/17 15:42:47 bigatti 659 // -- added include SparsePolyIter 660 // 661 // Revision 1.5 2018/02/27 17:30:22 abbott 662 // Summary: Renamed NumTheory_prime to NumTheory-prime; changed includes 663 // 664 // Revision 1.4 2018/02/27 10:56:39 abbott 665 // Summary: Added include NumTheory_prime 666 // 667 // Revision 1.3 2017/09/06 11:56:29 abbott 668 // Summary: Changed ERR::SERIOUS into ERR::ShouldNeverGetHere 669 // 670 // Revision 1.2 2016/01/27 14:00:26 abbott 671 // Summary: Added new pseudo-ctors which accept BigInts 672 // 673 // Revision 1.1 2015/12/18 15:25:07 abbott 674 // Summary: Added impls of non-prime finite fields 675 // 676 // 677