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