1 // Copyright (c) 1997-2007,2016,2018 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/MatrixFp.H"
19 #include "CoCoA/matrix.H"
20 #include "CoCoA/DenseMatrix.H"
21 #include "CoCoA/convert.H"
22 #include "CoCoA/RingFp.H"
23 #include "CoCoA/utils.H"
24 #include "CoCoA/VectorOps.H"
25 #include "CoCoA/verbose.H"
26
27 #include <iostream>
28 using std::endl;
29 #include <vector>
30 using std::vector;
31
32 // /* Two bits used in the return value */
33 // const int FFsolve_new_pivot = 2;
34 // const int FFsolve_invalid = 1;
35
36
37
38 /* Find a solution to a system of linear equations (in place). */
39 /* Several right hand side vectors may be specified. */
40 /* Method is just direct Gaussian elimination -- fine for finite fields */
41 /* The value returned is the rank of M. */
42 /* The result is placed in soln; if there is no solution for some rhs */
43 /* vector then its solution has first coordinate equal to p, the modulus.*/
44
45 namespace CoCoA
46 {
47
48
MatrixFp(const SmallFpImpl & ModP,int nrows,int ncols)49 MatrixFp::MatrixFp(const SmallFpImpl& ModP, int nrows, int ncols):
50 myRows(nrows),
51 myCols(ncols),
52 myArith(ModP),
53 myM(nrows, std::vector<SmallFpImpl::value>(ncols))
54 {}
55
56
MatrixFp(const ConstMatrixView & M)57 MatrixFp::MatrixFp(const ConstMatrixView& M):
58 myRows(NumRows(M)),
59 myCols(NumCols(M)),
60 myArith(ModularArith(RingOf(M))), // ASSUME small prime!!!
61 myM(myRows, std::vector<SmallFpImpl::value>(myCols))
62 {
63 for (int i=0; i < myRows; ++i)
64 for (int j=0; j < myCols; ++j)
65 myM[i][j] = myArith.myReduce(ConvertTo<long>(M(i,j)));
66 }
67
68
69
70
71
72 class MatrixFpNonRed
73 {
74 public:
75 MatrixFpNonRed(long nrows, long ncols);
76 // MatrixFpNonRed();
mySwapRows(long r1,long r2)77 void mySwapRows(long r1, long r2) {CoCoA_ASSERT(0 <= r1 && r1 < myRows && 0 <= r2 && r2 < myRows); if (r1 != r2) std::swap(myM[r1],myM[r2]);} ;
78 SmallFpImpl::NonRedValue& operator()(long r, long c);
79 const SmallFpImpl::NonRedValue& operator()(long r, long c) const;
80 // friend void SetEntry(MatrixFp& M, long r, long c, SmallFpImpl::value x);
81
82 private:
83 long myRows;
84 long myCols;
85 std::vector< std::vector< SmallFpImpl::NonRedValue > > myM;
86 };
87
MatrixFpNonRed(long nrows,long ncols)88 MatrixFpNonRed::MatrixFpNonRed(long nrows, long ncols):
89 myRows(nrows), // clang says unused???
90 myCols(ncols), // clang says unused???
91 myM(nrows, std::vector<SmallFpImpl::NonRedValue>(ncols))
92 {}
93
operator()94 inline SmallFpImpl::NonRedValue& MatrixFpNonRed::operator()(long r, long c) { return myM[r][c]; }
operator()95 inline const SmallFpImpl::NonRedValue& MatrixFpNonRed::operator()(long r, long c) const { return myM[r][c]; }
96
97
MulByTr(const MatrixFp & M1,const MatrixFp & trM2)98 MatrixFp MulByTr(const MatrixFp& M1, const MatrixFp& trM2)
99 {
100 CoCoA_ASSERT(ModPArith(M1) == ModPArith(trM2));
101 CoCoA_ASSERT(NumCols(M1) == NumCols(trM2)); // YES!!! I do mean NumCols(trM2)
102 const SmallFpImpl& ModP = ModPArith(M1);
103 MatrixFp ans(ModP, NumRows(M1), NumRows(trM2));
104 for (int i=0; i < NumRows(M1); ++i)
105 for (int j=0; j < NumRows(trM2); ++j)
106 {
107 SmallFpImpl::NonRedValue sum = zero(SmallFp);
108 for (int k=0; k < NumCols(M1); ++k)
109 sum += M1(i,k)*trM2(j,k); // BUG add overflow check!
110 ans(i,j) = ModP.myNormalize(sum);
111 }
112 return ans;
113 }
114
115
116 class LinSolver
117 {
118 public:
119 LinSolver(/*const SmallFpImpl& Modp,*/ const MatrixFp& M, const MatrixFp& rhs);
120 //?? LinSolver(const matrix& M, const matrix& rhs);
121 friend long rk(LinSolver& LS);
122 friend const MatrixFp& soln(/*const*/ LinSolver& LS);
123 private:
124 void SolveByGauss();
125 private: // data members
126 long myNrows;
127 long myNcols;
128 long myRHScols;
129 long myRank; // -1 means not yet solved, non-neg is true value
130 const SmallFpImpl& myModP;
131 MatrixFpNonRed myM; // matrix and rhs concatenated
132 MatrixFp mySoln;
133 std::vector<bool> mySolnIsValid;
134 std::vector<long> myPivotRow;
135 };
136
rk(LinSolver & LS)137 long rk(LinSolver& LS) { if (LS.myRank < 0) LS.SolveByGauss(); return LS.myRank; }
soln(LinSolver & LS)138 const MatrixFp& soln(/*const*/ LinSolver& LS) { if (LS.myRank < 0) LS.SolveByGauss(); return LS.mySoln;}
139
LinSolver(const MatrixFp & M,const MatrixFp & rhs)140 LinSolver::LinSolver(/*const SmallFpImpl& Modp,*/ const MatrixFp& M, const MatrixFp& rhs):
141 myNrows(NumRows(M)),
142 myNcols(NumCols(M)),
143 myRHScols(NumCols(rhs)),
144 myRank(-1),
145 myModP(ModPArith(M)),
146 myM(myNrows, myNcols+myRHScols),
147 mySoln(myModP, myNrows, myRHScols),
148 mySolnIsValid(myRHScols), /// ??? init val
149 myPivotRow(myNcols) ///??? init val?
150 {
151 CoCoA_ASSERT(NumRows(rhs) == myNrows);
152 // CoCoA_ASSERT(NumRows(rhs) == myNrows);
153 // Fill myM
154 for (int i=0; i < myNrows; ++i)
155 {
156 for (int j=0; j < myNcols; ++j)
157 {
158 myM(i,j) = M(i,j);
159 }
160 for (int j=0; j < myRHScols; ++j)
161 {
162 myM(i, j+myNcols) = rhs(i,j);
163 }
164 }
165 }
166
167 //int FFsolve(FFmat soln, int *shape, FFmat matrix, FFmat RHS)
168 //int LinSolveInPlace(vector<vector< SmallFpImpl::NonRedValue> >& M, int ncols)
SolveByGauss()169 void LinSolver::SolveByGauss()//const SmallFpImpl& Modp, MatrixFp& soln, const MatrixFp& M, const MatrixFp& rhs)
170 {
171 int ReducedRows = 0;
172 const int AllCols = myNcols+myRHScols;
173 const SmallFpImpl& Modp = myModP;
174 const long TimeToReduce = Modp.myMaxIters();
175 long count = 0;
176 // vector<int> PivotRow(ncols);
177 // pivot_row = (int*)MALLOC(ncols*sizeof(int));
178 // Do Gauss redn col-by-col from lhs
179 for (int i=0; i < myNcols; ++i)
180 {
181 bool ZeroCol = true;
182 SmallFpImpl::value pivot;
183 for (int j=ReducedRows; j < myNrows; ++j)
184 {
185 pivot = Modp.myNormalize(myM(j,i));
186 if (!IsZero(pivot)) { ZeroCol = false; break;}
187 }
188 if (ZeroCol)
189 {
190 /// if (shape[i]) { FREE(pivot_row); return FFsolve_invalid; }
191 continue;
192 }
193 // What does next block do????
194 // if (!shape[i])
195 // {
196 // shape[i] = 1;
197 // result |= FFsolve_new_pivot;
198 // for (k=i+1; k < ncols; ++k) shape[k] = 0;
199 // }
200 myPivotRow[ReducedRows] = i;
201 myM.mySwapRows(ReducedRows, i);
202 // swap = M[j]; M[j] = M[trows]; M[trows] = swap;
203 // swap = rhs[j]; rhs[j] = rhs[trows]; rhs[trows] = swap;
204 // const SmallFpImpl::value invMii = Modp.myRecip(myM(ReducedRows,i));
205 const SmallFpImpl::value inv_pivot = Modp.myRecip(pivot);
206 for (int j=i; j < AllCols; ++j)
207 myM(ReducedRows,j) = Modp.myMul(inv_pivot, Modp.myNormalize(myM(ReducedRows,j)));
208 // for (j=i; j < ncols; j++) M[trows][j] = FFmul(M[trows][j]%p, invMii);
209 // for (j=0; j < r; j++) rhs[trows][j] = FFmul(rhs[trows][j]%p, invMii);
210
211 // Now zero the whole column (except the pivot, of course!)
212 for (int j=0; j < myNrows; j++)
213 {
214 if (j == ReducedRows) continue;
215 SmallFpImpl::value Mji = Modp.myNormalize(myM(j,i));
216 if (IsZero(Mji)) continue;
217 Mji = Modp.myNegate(Mji);
218 for (int k=i+1; k < AllCols; ++k)
219 myM(j,k) += Mji*myM(ReducedRows,k);
220 // for (int k=0; k < r; k++) rhs[j][k] += Mji*rhs[trows][k];
221 // for (k=i+1; k < ncols; k++) M[j][k] += Mji*M[trows][k];
222 myM(j,i) = zero(SmallFp);
223 }
224 ++ReducedRows;
225 if (++count < TimeToReduce) continue;
226 count = 0;
227 for (int j=0; j < myNrows; ++j)
228 {
229 for (int k=i+1; k < AllCols; ++k)
230 myM(j,k) = Modp.myHalfNormalize(myM(j,k));
231 // for (k=0; k < r; k++)
232 // if (rhs[j][k] >= shift) rhs[j][k] -= shift;
233 // for (k=i+1; k < ncols; k++)
234 // if (M[j][k] >= shift) M[j][k] -= shift;
235 }
236 }
237
238 for (int j=0; j < myRHScols; ++j)
239 {
240 /* If any coord beyond ReducedRows is non-zero, no solution exists. */
241 for (int i=ReducedRows; i < myNrows; ++i)
242 {
243 myM(i, j+myNcols) = Modp.myNormalize(myM(i,j));
244 if (!IsZero(Modp.myNormalize(myM(i,j)))) { mySolnIsValid[j] = false; break; }
245 }
246 // There is a soln, so put it into mySoln:
247 int k = ReducedRows-1;
248 for (int i=myNcols-1; i >= 0; --i)
249 {
250 if (k >= 0 && i == myPivotRow[k])
251 { mySoln(i,j) = Modp.myNormalize(myM(k, j + myNcols)); --k; }
252 //default value!! else mySoln(i,j) = 0;
253 }
254 }
255
256 }
257
258
LinSolveFp(ConstMatrixView M,ConstMatrixView rhs)259 matrix LinSolveFp(ConstMatrixView M, ConstMatrixView rhs)
260 {
261 ring Fp = RingOf(M);
262 // assume RingOf(rhs) == Fp
263 // const int p = ConvertTo<long>(characteristic(Fp));
264 // SmallFpImpl Modp(p);
265 const SmallFpImpl& ModP = ModularArith(Fp);
266
267 const long rows = NumRows(M);
268 const long cols = NumCols(M);
269 const long rhs_cols = NumCols(rhs);
270 MatrixFp Mcopy(ModP, rows, cols);
271 MatrixFp RHScopy(ModP, rows, rhs_cols);
272 for (int i=0; i < rows; ++i)
273 for (int j=0; j < cols; ++j)
274 Mcopy(i,j) = ModP.myReduce(ConvertTo<long>(M(i,j)));
275 for (int i=0; i < rows; ++i)
276 for (int j=0; j < rhs_cols; ++j)
277 RHScopy(i,j) = ModP.myReduce(ConvertTo<long>(rhs(i,j)));
278 LinSolver LS(/*Modp,*/ Mcopy, RHScopy);
279 const MatrixFp& Msoln = soln(LS);
280 matrix ans = NewDenseMat(Fp, rows, rhs_cols);
281 for (int i=0; i < rows; ++i)
282 for (int j=0; j < rhs_cols; ++j)
283 SetEntry(ans,i,j, ModP.myExportNonNeg(Msoln(i,j)));
284 return ans;
285 }
286
287
LinKerFp(ConstMatrixView M_orig)288 matrix LinKerFp(ConstMatrixView M_orig)
289 {
290 ring Fp = RingOf(M_orig);
291 // assume RingOf(rhs) == Fp
292 // const int p = ConvertTo<long>(characteristic(Fp));
293 const SmallFpImpl& ModP = ModularArith(Fp);
294 // SmallFpImpl Modp(p);
295
296 const long nrows = NumRows(M_orig);
297 const long ncols = NumCols(M_orig);
298 MatrixFpNonRed M(nrows, ncols);
299 for (int i=0; i < nrows; ++i)
300 for (int j=0; j < ncols; ++j)
301 M(i,j) = ModP.myReduce(ConvertTo<long>(M_orig(i,j)));
302
303 vector<bool> c(nrows); // initially all false
304 vector<int> d(ncols); // initially all zero
305 vector<SmallFpImpl::value> ThisRow(ncols);
306
307 int KerDim = 0;
308 int IterCount = 0;
309
310 for (int k=0; k < ncols; ++k)
311 {
312 for (int j=0; j < nrows; ++j)
313 {
314 ThisRow[j] = ModP.myNormalize(M(j,k));
315 M(j,k) = ThisRow[j];
316 }
317
318 int j;
319 for (j=0; j < nrows; ++j)
320 if (!c[j] && !IsZero(ThisRow[j])) break;
321
322 if (j == nrows) { ++KerDim; d[k] = -1; continue; }
323 // Mj = M+(ncols*j);
324 const SmallFpImpl::value q = ModP.myNegate(ModP.myRecip(ThisRow[j])); // surely non-zero
325 for (int i=k+1; i < ncols; i++)
326 M(j,i) = ModP.myMul(q, ModP.myNormalize(M(j,i)));
327
328 for (int i=0; i < nrows; i++)
329 {
330 if (i == j) continue;
331 //Mi = M+(i*ncols);
332 const SmallFpImpl::value Mik = ModP.myNormalize(M(i,k));
333 if (IsZero(Mik)) continue;
334 M(i,k) = zero(SmallFp);
335 for (int s=k+1; s < ncols; s++)
336 M(i,s) += Mik*M(j,s);
337 /* for (s=k+1; s < ncols; s++) Mi[s] += Mik*Mj[s]; */
338 // {
339 // FFelem *Mis = &Mi[k+1],
340 // *Mjs = &Mj[k+1],
341 // *last = &Mi[ncols-1];
342 // while (Mis <= last) *(Mis++) += Mik * *(Mjs++);
343 // }
344 }
345 c[j] = true;
346 d[k] = j;
347 if (++IterCount < ModP.myMaxIters()) continue;
348 IterCount = 0;
349 for (int i=0; i < nrows; i++)
350 {
351 // Mi = M+(i*ncols);
352 for (int j=k+1; j < ncols; j++)
353 M(i,j) = ModP.myHalfNormalize(M(i,j));
354 // if (Mi[j] >= shift) Mi[j] -= shift;
355 }
356 }
357
358
359 // MatrixFp ans(KerDim, ncols);
360 matrix ans = NewDenseMat(Fp, KerDim, ncols);
361 // ans = (FFelem*)MALLOC(KerDim*ncols*sizeof(FFelem));
362 int s = 0;
363 // x = ans;
364 for (int k=0; k < ncols; ++k)
365 {
366 if (d[k] != -1) continue;
367 for (int i=0; i < ncols; ++i)
368 {
369 if (d[i] == -1) SetEntry(ans,s,i, (i == k));//ans(k,i) = ModP.myReduce(i == k);
370 else SetEntry(ans,s,i, ModP.myExport(ModP.myNormalize(M(d[i],k))));// ans(k,i) = ModP.myNormalize(M(d[i],k));
371 }
372 // x += ncols;
373 ++s;
374 }
375 // FREE(c);
376 // FREE(d);
377
378 // *B = ans;
379 return ans;
380
381 }
382
383 // class LinDepFp
384 // {
385 // public:
386 // LinDepFp(const SmallFpImpl& ModP, long dim);
387 // bool myAppendVec(std::vector<SmallFpImpl::value>& v);
388 // // bool IsLinDep() const { return };
389 // const std::vector<SmallFpImpl::value>& myLinReln() { CoCoA_ASSERT(); return myLinRelnVec;}
390
391 // private:
392 // const SmallFpImpl& myArith;
393 // long myDim;
394 // int myNumVecs;
395 // std::vector< std::vector<SmallFpImpl::value> > myM;
396 // std::vector<SmallFpImpl::NonRedValue> myRow;
397 // // std::vector<std::vector<RingElem> > myRowRepr;
398 // std::vector<int> myColIndices;
399 // std::vector<SmallFpImpl::value> myLinRelnVec;
400
401 // };
402
LinDepFp(const SmallFpImpl & ModP,long dim)403 LinDepFp::LinDepFp(const SmallFpImpl& ModP, long dim):
404 myArith(ModP),
405 myDim(dim),
406 myNumVecs(0),
407 myColIndices(dim,-1)
408 {
409 // if (!IsField(K)) CoCoA_ERROR(ERR::NotField, "LinDepMill ctor");
410 if (dim <= 0) CoCoA_ERROR(ERR::NotPositive, "LinDepFp ctor");
411 myM.reserve(dim);
412 myRow.reserve(2*dim);
413 myLinRelnVec.reserve(dim);
414 }
415
myAppendVec(std::vector<SmallFpImpl::value> & v)416 bool LinDepFp::myAppendVec(std::vector<SmallFpImpl::value>& v)
417 {
418 myLinRelnVec.clear(); // empty unless we find a lin reln
419 // VerboseLog VERBOSE("LinDepFp::myAppendVec");
420 // VERBOSE(10) << "Recvd vec " << v << endl;
421 CoCoA_ASSERT(len(v) == myDim);
422 for (int i=0; i < myDim; ++i)
423 {
424 myRow[i] = v[i];
425 myRow[i+myDim] = (i == myNumVecs)?one(SmallFp):zero(SmallFp);
426 }
427
428 int rightmost = 0;
429 const long p = myArith.myModulus();
430 const long SizeLimit = std::numeric_limits<SmallFpImpl::repr_t>::max()/p; // integer division
431 const long HalfWay_up = (1+SizeLimit)/2; // integer division!
432 long SizeEst = 1; // values in myRow are less than p*SizeEst
433 for (int c=0; c < myDim; ++c)
434 {
435 const SmallFpImpl::value entry = myArith.myNormalize(myRow[c]);
436 if (IsZero(entry)) { myRow[c] = entry; continue; }
437 if (myColIndices[c] < 0)
438 {
439 // We have a new reducer (and surely no lin dep)
440 vector<SmallFpImpl::value> NewRow(2*myDim);
441 const SmallFpImpl::value inv = myArith.myRecip(entry);
442 NewRow[c] = one(SmallFp);
443 const int END = myNumVecs+myDim;
444 for (int j=c+1; j <= END; ++j)
445 NewRow[j] = myArith.myMul(inv, myArith.myNormalize(myRow[j]));
446 // VERBOSE(10) << "New reducer for col " << c << " is " << NewRow << endl;
447 myM.push_back(NewRow);
448 myColIndices[c] = myNumVecs;
449 ++myNumVecs;
450 return false; // no lin dep
451 }
452
453 myRow[c] = zero(SmallFp);
454 const int reducer = myColIndices[c];
455 if (reducer > rightmost) rightmost = reducer;
456 // VERBOSE(10) << "Row redn for col " << c << " by vec " << reducer << " " << myM[reducer] << endl;
457 const SmallFpImpl::value scale = myArith.myNegate(entry);
458
459 SizeEst += myArith.myExportNonNeg(scale);
460 if (SizeEst > SizeLimit)
461 {
462 // Overflow is possible, so to avoid it we half-reduce entries in myRow
463 const int END2 = rightmost + myDim;
464 for (int j=c+1; j < END2; ++j)
465 myRow[j] = myArith.myHalfNormalize(myRow[j]);
466
467 SizeEst = HalfWay_up + myArith.myExportNonNeg(scale);
468 }
469
470 const vector<SmallFpImpl::value>& RedRow = myM[reducer];
471 const int END = reducer+myDim; // all later coords are zero
472 for (int j=c+1; j <= END; ++j)
473 myRow[j] += scale*RedRow[j];
474
475 }
476 // We have a lin dep; copy it into myLinRelnVec
477 myLinRelnVec.resize(1+myNumVecs);
478 myLinRelnVec[myNumVecs] = one(SmallFp);
479 for (int j=0; j < myNumVecs; ++j)
480 myLinRelnVec[j] = myArith.myNormalize(myRow[j+myDim]);
481
482 return true;
483 }
484
485
SignatureOfPerm(const vector<int> & perm)486 int SignatureOfPerm(const vector<int>& perm)
487 {
488 const int n = len(perm);
489 vector<bool> visited(n); // initially false
490 int sign = 1;
491 for (int i=0; i < n; ++i)
492 {
493 if (visited[i]) continue;
494 int CycleLen = 0;
495 int curr = i;
496 while (!visited[curr])
497 {
498 visited[curr] = true;
499 curr = perm[curr];
500 ++CycleLen;
501 }
502 if ((CycleLen&1) == 0) sign = -sign;
503 }
504 return sign;
505 }
506
507
det(MatrixFp & M)508 long/*SmallFpImpl::value*/ det(MatrixFp& M)
509 {
510 const SmallFpImpl& ModP = ModPArith(M);
511 const long p = ModP.myModulus();
512 const long SizeLimit = std::numeric_limits<SmallFpImpl::repr_t>::max()/p; // integer division
513 const long HalfWay_up = (1+SizeLimit)/2; // integer division!
514 long SizeEst = 1; // values in myRow are less than p*SizeEst
515 const int n = NumRows(M);
516 vector<int> ReducerIndex(n,-1); // -1 means no reducer
517 vector<SmallFpImpl::NonRedValue> CurrRow(n);
518 SmallFpImpl::value DiagProd = one(SmallFp);
519 for (int row=0; row < n; ++row)
520 {
521 //CurrRow = M[row];
522 for (int col=0; col < n; ++col)
523 CurrRow[col] = M(row,col);
524 bool HaveNewReducerRow = false;
525 for (int col=0; col < n; ++col)
526 {
527 const SmallFpImpl::value entry = ModP.myNormalize(CurrRow[col]);
528 if (IsZero(entry)) { CurrRow[col] = entry; continue; }
529 const int reducer = ReducerIndex[col];
530 if (reducer >= 0)
531 {
532 CurrRow[col] = zero(SmallFp);
533 // VERBOSE(10) << "Row redn for col " << c << " by vec " << reducer << " " << myM[reducer] << endl;
534 const SmallFpImpl::value scale = ModP.myNegate(entry);
535
536 SizeEst += ModP.myExportNonNeg(scale);
537 // if (SizeEst <= SizeLimit)
538 // {
539 // const vector<SmallFpImpl::value>& RedRow = M[reducer];
540 // for (int j=col+1; j < n; ++j)
541 // CurrRow[j] += scale*RedRow[j];
542 // // SmallFpImpl::NonRedValue* Rj = &CurrRow[col+1];
543 // // SmallFpImpl::NonRedValue* END = &CurrRow[n];
544 // // SmallFpImpl::value* mij = &M[reducer][col+1];
545 // // while (Rj != END)
546 // // *Rj++ = scale * *mij++;
547 // continue;
548 // }
549 if (SizeEst > SizeLimit)
550 {
551 // Overflow is possible, so to avoid it we half-reduce entries in myRow
552 for (int j=col+1; j < n; ++j)
553 CurrRow[j] = ModP.myHalfNormalize(CurrRow[j]);
554
555 SizeEst = HalfWay_up + ModP.myExportNonNeg(scale);
556 }
557
558 const vector<SmallFpImpl::value>& RedRow = M[reducer];
559 for (int j=col+1; j < n; ++j)
560 CurrRow[j] += scale*RedRow[j];
561 continue;
562 }
563 if (ReducerIndex[col] < 0)
564 {
565 // We have a new reducer
566 HaveNewReducerRow = true;
567 const SmallFpImpl::value inv = ModP.myRecip(entry);
568 DiagProd = ModP.myMul(DiagProd, entry);
569 // vector<SmallFpImpl::value>& Mrow = M[row];
570 for (int j=0; j < col; ++j)
571 M(row,j)/*Mrow[j]*/ = zero(SmallFp);
572 M(row,col)/*Mrow[col]*/ = one(SmallFp);
573 for (int j=col+1; j < n; ++j)
574 M(row,j)/*Mrow[j]*/ = ModP.myMul(inv, ModP.myNormalize(CurrRow[j]));
575 // VERBOSE(10) << "New reducer for col " << c << " is " << NewRow << endl;
576 ReducerIndex[col] = row;
577 break;
578 }
579
580
581 }
582 if (!HaveNewReducerRow) return 0; //zero(SmallFp);
583 }
584 if (SignatureOfPerm(ReducerIndex) == 1)
585 return ModP.myExportNonNeg(DiagProd);
586 return ModP.myModulus() - ModP.myExportNonNeg(DiagProd);
587 }
588
589
RowRednFp(const SmallFpImpl & ModP,long dim)590 RowRednFp::RowRednFp(const SmallFpImpl& ModP, long dim):
591 myArith(ModP),
592 myDim(dim),
593 myNumVecs(0),
594 myDiagProd(one(SmallFp)),
595 myColIndices(dim,-1)
596 {
597 // if (!IsField(K)) CoCoA_ERROR(ERR::NotField, "LinDepMill ctor");
598 if (dim <= 0) CoCoA_ERROR(ERR::NotPositive, "RowRednFp ctor");
599 myM.reserve(dim);
600 myRow.reserve(2*dim);
601 // myLinRelnVec.reserve(dim);
602 }
603
myAppendVec(std::vector<SmallFpImpl::value> & v)604 void RowRednFp::myAppendVec(std::vector<SmallFpImpl::value>& v)
605 {
606 // myLinRelnVec.clear(); // empty unless we find a lin reln
607 // VerboseLog VERBOSE("RowRednFp::myAppendVec");
608 // VERBOSE(10) << "Recvd vec " << v << endl;
609 CoCoA_ASSERT(len(v) == myDim);
610 for (int i=0; i < myDim; ++i)
611 {
612 myRow[i] = v[i];
613 // myRow[i+myDim] = (i == myNumVecs)?one(SmallFp):zero(SmallFp);
614 }
615
616 // int rightmost = 0;
617 const long p = myArith.myModulus();
618 const long SizeLimit = std::numeric_limits<SmallFpImpl::repr_t>::max()/p; // integer division
619 const long HalfWay_up = (1+SizeLimit)/2; // integer division!
620 long SizeEst = 1; // values in myRow are less than p*SizeEst
621 for (int c=0; c < myDim; ++c)
622 {
623 const SmallFpImpl::value entry = myArith.myNormalize(myRow[c]);
624 if (IsZero(entry)) { myRow[c] = entry; continue; }
625 if (myColIndices[c] < 0)
626 {
627 // We have a new reducer
628 vector<SmallFpImpl::value> NewRow(myDim);
629 const SmallFpImpl::value inv = myArith.myRecip(entry);
630 myDiagProd = myArith.myMul(myDiagProd, entry);
631 NewRow[c] = one(SmallFp);
632 // const int END = myNumVecs+myDim;
633 for (int j=c+1; j < myDim; ++j)
634 NewRow[j] = myArith.myMul(inv, myArith.myNormalize(myRow[j]));
635 // VERBOSE(10) << "New reducer for col " << c << " is " << NewRow << endl;
636 myM.push_back(NewRow);
637 myColIndices[c] = myNumVecs;
638 ++myNumVecs;
639 return;
640 }
641
642 myRow[c] = zero(SmallFp);
643 const int reducer = myColIndices[c];
644 // if (reducer > rightmost) rightmost = reducer;
645 // VERBOSE(10) << "Row redn for col " << c << " by vec " << reducer << " " << myM[reducer] << endl;
646 const SmallFpImpl::value scale = myArith.myNegate(entry);
647
648 SizeEst += myArith.myExportNonNeg(scale);
649 if (SizeEst > SizeLimit)
650 {
651 // Overflow is possible, so to avoid it we half-reduce entries in myRow
652 // const int END2 = rightmost + myDim;
653 for (int j=c+1; j < myDim; ++j)
654 myRow[j] = myArith.myHalfNormalize(myRow[j]);
655
656 SizeEst = HalfWay_up + myArith.myExportNonNeg(scale);
657 }
658
659 const vector<SmallFpImpl::value>& RedRow = myM[reducer];
660 // const int END = reducer+myDim; // all later coords are zero
661
662 for (int j=c+1; j < myDim; ++j)
663 myRow[j] += scale*RedRow[j];
664
665 // SmallFpImpl::NonRedValue* dest = &myRow[c+1];
666 // const SmallFpImpl::value* reduce = &RedRow[c+1];
667 // SmallFpImpl::NonRedValue* const END = &myRow[myDim+1];
668 // while (dest != END)
669 // *dest++ += scale * *reduce++;
670
671 }
672 // // We have a lin dep; copy it into myLinRelnVec
673 // myLinRelnVec.resize(1+myNumVecs);
674 // myLinRelnVec[myNumVecs] = one(SmallFp);
675 // for (int j=0; j < myNumVecs; ++j)
676 // myLinRelnVec[j] = myArith.myNormalize(myRow[j+myDim]);
677
678 return;
679 }
680
myRank()681 long RowRednFp::myRank() const
682 {
683 return myNumVecs;
684 }
685
myDet()686 SmallFpImpl::value RowRednFp::myDet() const
687 {
688 CoCoA_ASSERT(myNumVecs == myDim); // BUG, should count number of calls!!!
689 if (myNumVecs < myDim) return zero(SmallFp);
690 if (SignatureOfPerm(myColIndices) == 1)
691 return myDiagProd; // sign???
692 else
693 return myArith.myNegate(myDiagProd);
694 }
695
696 } // end of namespace CoCoA
697