Macaulay2 Engine
Loading...
Searching...
No Matches
NCF4.cpp
Go to the documentation of this file.
1#include "NCAlgebras/NCF4.hpp"
2
3#include "text-io.hpp" // for emit_wrapped
4#include "NCAlgebras/FreeAlgebra.hpp" // for FreeAlgebra
5#include "NCAlgebras/OverlapTable.hpp" // for OverlapTable
6#include "VectorArithmetic.hpp" // for VectorArithmetic
7#include "NCAlgebras/WordTable.hpp" // for Overlap, WordTable
8#include "buffer.hpp" // for buffer
9#include "interface/m2-types.h" // for M2_gbTrace
10#include "ring.hpp" // for Ring
11#include "ringelem.hpp" // for ring_elem
12#include "../system/supervisorinterface.h" // for getAllowableThreads
13
14#include <cassert> // for assert
15#include <cstdlib> // for exit, size_t
16#include <algorithm> // for copy
17#include <iostream> // for operator<<, basic_ostream
18
20 const ConstPolyList& input,
21 int hardDegreeLimit,
22 int strategy,
23 int numThreads // 0 for tbb::info::default_concurrency(), for now
24 )
25 : mFreeAlgebra(A),
26 mInput(input),
27 //mTopComputedDegree(-1), // not used yet.
28 //mHardDegreeLimit(hardDegreeLimit), // not used yet.
29 mMonomEq(A.monoid()),
30 mMonomHashEqual(A.monoid()),
33 mVectorArithmetic(new VectorArithmetic(A.coefficientRing())),
34 mNumThreads(mtbb::numThreads(numThreads)),
37{
38 // std::cout << "number of processors being used: " << mNumThreads << std::endl;
39 (void) hardDegreeLimit;
40 (void) strategy;
41 if (M2_gbTrace >= 1)
42 {
43 buffer o;
44 o << "[NCGB F4]";
45 emit_wrapped(o.str());
46 }
47
48 // process input polynomials
49 mIsGraded = true;
50 for (int i = 0; i < mInput.size(); ++i)
51 {
52 auto d = freeAlgebra().heft_degree(*mInput[i]);
53 if (not d.second)
54 mIsGraded = false;
55 mOverlapTable.insert(d.first,
56 true,
57 std::make_tuple(i,-1,-1,true));
58 }
59 if (M2_gbTrace >= 1)
60 {
61 buffer o;
62 o << (mIsGraded ? " homogeneous " : " inhomogeneous ");
63 emit_wrapped(o.str());
64 }
65}
66
67void NCF4::compute(int softDegreeLimit)
68{
69 while (!mOverlapTable.isFinished(softDegreeLimit))
70 {
71 auto degSet = mOverlapTable.nextDegreeOverlaps();
72 auto toBeProcessed = degSet.second;
73 if (M2_gbTrace >= 1)
74 {
75 buffer o;
76 o << "{" << degSet.first << "}(" << toBeProcessed->size() << ")";
77 emit_wrapped(o.str());
78 }
79 mScheduler.execute([this,&toBeProcessed]()
80 {
81 process(*toBeProcessed);
82 });
83
84 mOverlapTable.removeLowestDegree(); // TODO: suspect line.
85 // we really want to just delete toBeProcessed...
86 }
87}
88
89void NCF4::process(const std::deque<Overlap>& overlapsToProcess)
90{
91#if 0
92 if (M2_gbTrace >= 2)
93 {
94 buffer o;
95 o << newline << "F4 processing: # overlaps (spairs): " << overlapsToProcess.size() << newline;
96 emit(o.str());
97 }
98#endif
99
100 // build the F4 matrix
101 mtbb::tick_count t0 = mtbb::tick_count::now();
102 // if (mIsParallel)
103 // parallelBuildF4Matrix(overlapsToProcess);
104 // else
105 buildF4Matrix(overlapsToProcess);
106 mtbb::tick_count t1 = mtbb::tick_count::now();
107 if (M2_gbTrace >= 2)
108 std::cout << "Time spent on build step: " << (t1-t0).seconds() << std::endl;
109
110 if (M2_gbTrace >= 2)
111 {
112 std::cout << "NC F4 GB: matrix size: ";
113 displayF4MatrixSize(std::cout);
114 }
115
116 // sort the columns so that the matrix is `upper triangular'
118
119 if (M2_gbTrace >= 100) displayFullF4Matrix(std::cout);
120 else if (M2_gbTrace >= 50) displayF4Matrix(std::cout);
121
122 // reduce the matrix
123 t0 = mtbb::tick_count::now();
124 if (mIsParallel)
126 else
128 t1 = mtbb::tick_count::now();
129 if (M2_gbTrace >= 2)
130 std::cout << "Time spent on reduction step: " << (t1-t0).seconds() << std::endl;
131
132 if (M2_gbTrace >= 100) displayFullF4Matrix(std::cout);
133 else if (M2_gbTrace >= 50) displayF4Matrix(std::cout);
134
135 // convert back to GB elements...
136 PolyList newElems = newGBelements();
137
138 for (auto& f : newElems)
139 {
142 }
143
144 // prepare reduced matrix for use in the next degree
146
147#if 0
148 if (M2_gbTrace >= 2)
149 {
150 buffer o;
151 o << "F4 processing: # GB added: " << newElems.size() << newline;
152 o << "F4 processing: # GB total: " << mGroebner.size() << newline;
153 emit(o.str());
154 }
155#endif
156
157}
158
160{
161 // flag the columns correspond to lead terms of new GB elements as reducers
162 for (int i = mFirstOverlap; i < mRows.size(); ++i)
163 {
164 if (mRows[i].columnIndices.size() == 0) continue;
165 int newReducerCol = mRows[i].columnIndices[0];
166 mColumns[newReducerCol].pivotRow = i;
167 mColumnMonomials[mColumns[newReducerCol].word].second = i;
168 }
169
170 // copy the finished rows and columns into the holding areas
172 mPreviousColumns.clear();
174 mPreviousMonomialSpace.deallocateAll();
175
176 for (auto& p : mPreviousMemoryBlocks)
177 {
178 if (p != nullptr)
179 p->deallocateAll();
180 p = nullptr;
181 }
182 mPreviousMemoryBlocks.clear();
183
184 mPreviousRows = std::move(mRows);
185 mPreviousColumns = std::move(mColumns);
188 // need to move mMonomialSpace to a holding area since all the monomials
189 // and int arrays in mPrevious data types are allocated there.
191}
192
194{
195 mGroebner.push_back(toAdd);
196}
197
198void NCF4::updateOverlaps(const Poly * toAdd)
199{
200 std::vector<Overlap> newLeftOverlaps;
201 std::vector<Overlap> newRightOverlaps;
202
203 Word newLeadWord = freeAlgebra().lead_word(*toAdd);
204
205 // the word table insert places the right overlaps into newOverlaps
206 mWordTable.insert(newLeadWord,newRightOverlaps);
207
208 // this function finds the left overlaps with the most recently
209 // inserted word.
210 mWordTable.leftOverlaps(newLeftOverlaps);
211
212 // can *also* remove previously added overlaps based on poly using
213 // the same criterion from before
214 checkOldOverlaps(newLeadWord);
215
216 // finally, insert the new overlaps
217 insertNewOverlaps(newRightOverlaps);
218 insertNewOverlaps(newLeftOverlaps);
219
220}
221
222auto NCF4::overlapHeft(Overlap o) const -> int
223// overlap: of a pair of words v, w, v = a*s, w = s*b, returns the
224// heft degree of a*s*b.
225// o = triple (index of left GB element, pos, index of right GB element,
226// pos is the location in left GB element where s starts.
227{
228 Word tmpL = mWordTable[std::get<0>(o)];
229 Word tmpR = mWordTable[std::get<2>(o)];
230 int len_of_s = tmpL.size() - std::get<1>(o);
231 return freeAlgebra().monoid().wordHeft(tmpL) +
232 freeAlgebra().monoid().wordHeft(tmpR, len_of_s);
233}
234
235auto NCF4::insertNewOverlaps(std::vector<Overlap>& newOverlaps) -> void
236{
237 for (auto newOverlap : newOverlaps)
238 {
239 if (std::get<1>(newOverlap) != -1 && !isOverlapNecessary(newOverlap))
240 {
241 if (M2_gbTrace >= 3)
242 std::cout << "Reduction avoided using eager 2nd criterion." << std::endl;
243 continue;
244 }
245 mOverlapTable.insert(overlapHeft(newOverlap),
246 false,
247 newOverlap);
248 }
249}
250
251auto NCF4::isOverlapNecessary(const Overlap& o) -> bool
252{
253 // this function tests if the lead word of the overlap polynomial
254 // of o is a multiple of another pattern in the word table.
255
256 // need to be careful, however, since an overlap lead word is trivially
257 // a multiple of the words used to build it. These possibilities must be discarded
258 bool retval;
259 Word w;
260
261 // not optimal. Should pass information to wordTable for checking.
263 retval = !mWordTable.isNontrivialSuperword(w, std::get<0>(o), std::get<2>(o));
264 return retval;
265}
266
267auto NCF4::checkOldOverlaps(Word& newLeadWord) -> void
268{
269 // this function flags any previous overlaps that properly
270 // contain newLeadWord as no longer necessary.
271
272 // the newest overlaps are not yet added at this point
273 std::vector<int> startIndices;
274
275 for (auto& p : mOverlapTable.overlapMap())
276 {
277 for (auto& o : p.second)
278 {
279 if (not std::get<3>(o)) continue;
280 if (std::get<1>(o) == -1) continue;
281 int overlapLen = std::get<1>(o) + mWordTable[std::get<2>(o)].size();
282 if (overlapLen <= newLeadWord.size()) continue;
283 startIndices.clear();
284 // this is not optimal. Should pass info to word table to avoid creation of another word
285 auto w = createOverlapLeadWord(o);
286 WordTable::subwordPositions(newLeadWord,w,startIndices);
287 for (auto j : startIndices)
288 {
289 if (j != 0 or j != w.size() - newLeadWord.size())
290 {
291 if (M2_gbTrace >= 3)
292 std::cout << "Reduction avoided using lazy 2nd criterion." << std::endl;
293 std::get<3>(o) = false;
294 break;
295 }
296 }
297 }
298 }
299}
300
302{
303 // this function adds the return value to mMemoryBlock, so should only be used
304 // when running a GB since it will be subsequently cleared.
305 Word left(mWordTable[std::get<0>(o)].begin(),
306 mWordTable[std::get<0>(o)].begin()+std::get<1>(o));
307 Word right = mWordTable[std::get<2>(o)];
308 int sz = left.size() + right.size();
309 auto rg = mMonomialSpace.allocateArray<int>(sz);
310 std::copy(left.begin(),left.end(),rg.first);
311 std::copy(right.begin(),right.end(),rg.first+left.size());
312 return Word(rg.first, rg.second);
313}
314
315PolyList NCF4::newGBelements() const // From current F4 matrix.
316{
318 for (int i = mFirstOverlap; i < mRows.size(); i++)
319 {
320 if (mRows[i].columnIndices.size() == 0) continue;
321 Poly* f = new Poly;
323 result.push_back(f);
324 }
325 return result;
326}
327
329 const RowsVector& rows,
330 const ColumnsVector& cols,
331 int i) const
332{
333 // this function places the elements of the ith row of the
334 // (reduced!) F4 matrix in result. This assumes that the first
335 // term of the ith row is after the last entry of result (or that result is empty).
336 auto& resultCoeffInserter = result->getCoeffInserter();
337 auto& resultMonomInserter = result->getMonomInserter();
338
339 //mVectorArithmetic->appendSparseVectorToContainer(rows[i].first,resultCoeffInserter);
340 using ContainerType = decltype(resultCoeffInserter);
341 mVectorArithmetic->appendToContainer<ContainerType>(rows[i].coeffVector,resultCoeffInserter);
342
343 for (const auto& col : rows[i].columnIndices)
344 freeAlgebra().monoid().monomInsertFromWord(resultMonomInserter,cols[col].word);
345}
346
347ring_elem NCF4::getCoeffOfMonom(const Poly& f, const Monom& m) const
348{
349 for (auto t = f.cbegin(); t != f.cend(); ++t)
350 {
351 if (freeAlgebra().monoid().isEqual(t.monom(),m))
352 return t.coeff();
353 }
354 return freeAlgebra().coefficientRing()->zero();
355}
356
357// this function is not used currently. and is probably leaky as written (see the swap)
359{
360 if (mGroebner.size() <= 1) return;
361 const Poly& lastPoly = *(mGroebner[mGroebner.size()-1]);
362 Monom leadMon = lastPoly.cbegin().monom();
363 for (auto fPtr = mGroebner.begin(); fPtr != mGroebner.end() - 1; ++fPtr)
364 {
365 ring_elem foundCoeff = getCoeffOfMonom(**fPtr,leadMon);
366 if (!freeAlgebra().coefficientRing()->is_zero(foundCoeff))
367 {
368 Poly* result = new Poly;
369 freeAlgebra().subtractScalarMultipleOf(*result,**fPtr,lastPoly,foundCoeff);
370 freeAlgebra().swap(**fPtr,*result);
371 }
372 }
373}
374
376{
377 mReducersTodo.clear();
378 mOverlapsTodo.clear();
379 mColumns.clear();
380 mColumnMonomials.clear();
382 // we don't have to call clearRows on mOverlaps because the coeff vectors
383 // were moved to mRows first
384 mOverlaps.clear();
385 mFirstOverlap = 0;
386 mMonomialSpace.deallocateAll();
387
388 // the MemoryBlock objects that were in this vector
389 // have been passed to mPreviousMemoryBlocks at this point.
390 mMemoryBlocks.clear();
391}
392
394{
395 // o = (gbLeftIndex, overLapPos, gbRightIndex).
396 // BUT: if overlapPos < 0, then gbRightIndex is also < 0 (and is ignored), and gbLeftIndex
397 // refers to a generator, and we add to mOverlapsTodo in only (1,gbLeftIndex,1).
398 // where 1 = empty word.
399
400 int gbLeftIndex = std::get<0>(o);
401 int overlapPos = std::get<1>(o);
402 int gbRightIndex = std::get<2>(o);
403
404 if (overlapPos < 0)
405 {
406 // Sneaky trick: a PreRow with index a < 0 refers to generator with index -a-1
407 mOverlapsTodo.emplace_back(PreRow {Word(),
408 - gbLeftIndex - 1,
409 Word(),
411 return;
412 }
413
414 // LM(gbLeft) = x^a x^b
415 // LM(gbRight) = x^b x^c
416 // overlapPos = starting position of x^b in gbLeft.
417 // one prerow will be: (1, gbLeftIndex, x^c)
418 // another prerow will be: (x^a, gbRightIndex, 1)
419
420 Word leadWordLeft = mWordTable[gbLeftIndex];
421 Word leadWordRight = mWordTable[gbRightIndex];
422 int overlapLen = leadWordLeft.size() - overlapPos;
423
424 Word suffix2 {}; // trivial word
425 Word prefix2(leadWordLeft.begin(), leadWordLeft.begin() + overlapPos);
426
427 Word suffix1(leadWordRight.begin() + overlapLen, leadWordRight.end());
428 Word prefix1 {}; // trivial word
429
430 // need to add in the lead monomial to the mColumnMonomials list now
431 // so they know which row reduces them
432 Word newWord = freeAlgebra().monoid().wordProductAsWord(leadWordLeft, suffix1, mMonomialSpace);
433
434 // This overlap may already have lead term in table.
435 // Only have to add it in if it is not yet present.
436 auto it = mColumnMonomials.find(newWord);
437 if (it == mColumnMonomials.cend())
438 mColumnMonomials.emplace(newWord, std::make_pair(-1,-1));
439
440 // it *matters* which one is a reducer and which one is an overlap.
441 // this is due to how the word table lookup works -- it searches them
442 // in the order that they were entered into the word table, which may
443 // not be sorted in term order.
444 if (gbLeftIndex > gbRightIndex)
445 {
446 mReducersTodo.emplace_back(PreRow {prefix2,
447 gbRightIndex,
448 suffix2,
450 mOverlapsTodo.emplace_back(PreRow {prefix1,
451 gbLeftIndex,
452 suffix1,
454 }
455 else
456 {
457 mReducersTodo.emplace_back(PreRow {prefix1,
458 gbLeftIndex,
459 suffix1,
461 mOverlapsTodo.emplace_back(PreRow {prefix2,
462 gbRightIndex,
463 suffix2,
465 }
466}
467
468void NCF4::buildF4Matrix(const std::deque<Overlap>& overlapsToProcess)
469{
470 matrixReset();
471
472 mColumnMonomials.rehash(pow(2, ceil(log2(mPreviousColumnMonomials.size()))));
473
474 for (auto o : overlapsToProcess)
475 {
476 auto stillValid = std::get<3>(o);
477 if (stillValid) preRowsFromOverlap(o);
478 }
479
480 // can't do this loop as a range-based for loop since we are adding to it
481 // during the for loop
482 // process each element in mReducersTodo (false indicates a reducer row)
483 for (int i=0 ; i < mReducersTodo.size(); ++i)
484 processPreRow(mReducersTodo[i],mRows); // this often adds new elements to mReducersTodo
485
486 int numReducersAtFirst = mReducersTodo.size();
487
488 // process the overlap rows (true indicates an overlap row)
489 for (auto over : mOverlapsTodo)
490 processPreRow(over,mOverlaps); // this often adds new elements to mReducersTodo
491
492 // can't do this loop as a range-based for loop since we are adding
493 // to mReducersTodo during the for loop
494 for (int i=numReducersAtFirst ; i < mReducersTodo.size(); ++i)
495 processPreRow(mReducersTodo[i],mRows); // this often adds new elements to mReducersTodo
496
497 // Now we move the overlaps into mRows, and set mFirstOverlap.
498 // double range, so use a for loop
499 mFirstOverlap = mRows.size();
500 for (int i=0; i < mOverlapsTodo.size(); ++i)
501 {
502 mRows.emplace_back(mOverlaps[i]);
503 mReducersTodo.emplace_back(mOverlapsTodo[i]);
504 }
505}
506
507// this is currently not used in the process function
508// since it is not as fast as the serial version due
509// concurrency overhead.
510void NCF4::parallelBuildF4Matrix(const std::deque<Overlap>& overlapsToProcess)
511{
512 matrixReset();
513
514 mColumnMonomials.rehash(pow(2, ceil(log2(mPreviousColumnMonomials.size()))));
515
516 for (auto o : overlapsToProcess)
517 {
518 auto stillValid = std::get<3>(o);
519 if (stillValid) preRowsFromOverlap(o);
520 }
521
522 struct ThreadData {
523 RowsVector rowsVector;
524 MemoryBlock* memoryBlock;
525 };
526
527 mtbb::enumerable_thread_specific<ThreadData> threadData([&](){
528 mtbb::queuing_mutex::scoped_lock myColumnLock(mColumnMutex);
529 ThreadData data;
530 data.memoryBlock = new MemoryBlock;
531 mMemoryBlocks.push_back(data.memoryBlock);
532 return data;
533 });
534
535 // can't do this loop as a range-based for loop since we are adding to it
536 // during the for loop
537 // process each element in mReducersTodo
538
539 mtbb::parallel_for_each(mReducersTodo.begin(), mReducersTodo.end(),
540 [&](const PreRow& prerow, PreRowFeeder& feeder)
541 {
542 auto& data = threadData.local();
543 processPreRow(prerow,
544 data.rowsVector,
545 *data.memoryBlock,
546 &feeder);
547 });
548
549 // combine the thread local rows into mRows
550 for (const auto& data : threadData)
551 {
552 mRows.reserve(mRows.size() + data.rowsVector.size());
553 std::move(data.rowsVector.begin(),
554 data.rowsVector.end(),
555 std::back_inserter(mRows));
556 }
557
558 // WARNING: The feeder doesn't actually add things to mReducersTodo
559 // so in this algorithm there is now a disconnect between the
560 // sizes of mReducersTodo and mRows.
561
562 int numReducersAtFirst = mReducersTodo.size();
563
564 // this can be a parallel_for
565 for (auto over : mOverlapsTodo)
566 processPreRow(over,mOverlaps); // this often adds new elements to mReducersTodo
567
568 // this must (eventually) be a parallel_for_each
569 // can't do this loop as a range-based for loop since we are adding
570 // to mReducersTodo during the for loop
571 for (int i=numReducersAtFirst ; i < mReducersTodo.size(); ++i)
572 processPreRow(mReducersTodo[i],mRows); // this often adds new elements to mReducersTodo
573
574 // Now we move the overlaps into mRows, and set mFirstOverlap.
575 mFirstOverlap = mRows.size();
576 for (int i=0; i < mOverlapsTodo.size(); ++i)
577 {
578 mRows.emplace_back(mOverlaps[i]);
579 mReducersTodo.emplace_back(mOverlapsTodo[i]);
580 }
581}
582
584 RowsVector& rowsVector,
585 MemoryBlock& memoryBlock,
586 PreRowFeeder* feeder)
587{
588 // note: left and right should be the empty word if gbIndex < 0 indicating
589 // an input polynomial.
590 Word left = r.left;
591 int gbIndex = r.preRowIndex;
592 Word right = r.right;
593 PreRowType preRowType = r.preRowType;
594
595 if (M2_gbTrace >= 100)
596 std::cout << "Processing PreRow: ("
597 << left << "," << gbIndex << "," << right << ")"
598 << std::endl;
599
600 // construct the elem corresponding to this prerow
601 // it will either be:
602 // a multiple of a previously reduced row (if prevReducer)
603 // an element of the input (if gbIndex < 0 and not prevReducer)
604 // a multiple of a gb element (if gbIndex >= 0 and not prevReducer)
605 const Poly* elem;
606 Poly* tempelem;
607 if (preRowType == PreviousReducerPreRow)
608 {
609 // in this case, we construct the poly locally for processing in this
610 // function. We will destroy it at the end, as the new monomials for reduction
611 // are created and inserted into mMonomialSpace
612 tempelem = new Poly;
614 elem = tempelem;
615 }
616 else
617 {
618 if (gbIndex < 0)
619 elem = mInput[-gbIndex-1];
620 else
621 elem = mGroebner[gbIndex];
622 }
623
624 // loop through all monomials of the product
625 // for each monomial:
626 // (the below steps are now in processMonomInPreRow)
627 // is its prefix or suffix the lead term of a row from the previous degree?
628 // if so: insert the information from this row in the appropriate places
629 // if not: is the monomial in the hash table?
630 // if so: return the column index into the component for the new row.
631 // if not: insert it, and return the new column index into same place
632 // and place this monomial into mColumns.
633 // and search for divisor for it.
634 //
635 int numTerms = elem->numTerms();
636
637 auto wordRange = memoryBlock.allocateArray<Word>(numTerms);
638 auto columnRange = memoryBlock.allocateArray<int>(numTerms);
639 // int* componentAlloc = (int*)mMemoryPool.malloc(numTerms*sizeof(int));
640 // Range<int> componentRange(componentAlloc,componentAlloc + numTerms);
641 // for (auto& i : componentRange) i = 0;
642
643 Word* nextColWord = wordRange.first;
644
645 for (auto i = elem->cbegin(); i != elem->cend(); ++i)
646 {
647 Word mid;
648 freeAlgebra().monoid().wordFromMonom(mid,i.monom());
649 Word w = freeAlgebra().monoid().wordProductAsWord(left,mid,right,memoryBlock);
650 processWordInPreRow(w,feeder);
651 *nextColWord = w;
652 ++nextColWord;
653 }
654
655 // this memory is stored in rowsVector and cleaned up later.
656 ElementArray coeffs = mVectorArithmetic->elementArrayFromContainer(elem->getElementArray());
657
658 // delete the Poly created for prevReducer case, if necessary.
659 if (preRowType == PreviousReducerPreRow)
660 {
661 mFreeAlgebra.clear(*tempelem);
662 delete tempelem;
663 }
664
665 // add the processed row to the appropriate list
666 rowsVector.emplace_back(Row {coeffs, columnRange, wordRange});
667}
668
670 RowsVector& rowsVector)
671{
673 rowsVector,
675 nullptr);
676}
677
679 PreRowFeeder* feeder)
680{
681 const auto it = mColumnMonomials.find(w);
682 if (it == mColumnMonomials.end())
683 {
684 // if we are here, this monomial is not yet accounted for in the matrix
685 // so, check if the monomial is a multiple of a lead term of a gb element
686
687 // insert column information into mColumnMonomials,
688 // which provides us search (and eventually) indexing of columns
689 mColumnMonomials.emplace(w,std::make_pair(-1,-1));
690 auto divresult = findDivisor(w);
691 if (divresult.first)
692 {
693 // if m is a divisor of a gb element (or a left/right
694 // variable multiple of a previous reducer), add that
695 // multiple of the GB element to mReducersToDo for
696 // processing
697
698 // if feeder is nullptr, then this is a computation on a list
699 // not being added to during the loop.
700 // e.g. either F4 serial or overlaps processing
701 // otherwise, we must use the feeder to add more work.
702 if (feeder == nullptr)
703 mReducersTodo.push_back(divresult.second);
704 else
705 feeder->add(divresult.second);
706 }
707 }
708}
709
710std::pair<bool, NCF4::PreRow> NCF4::findDivisor(Word word)
711{
712 Word newword;
713
714 // look in previous F4 matrix for Monom before checking mWordTable
715
716 auto usePreviousSuffix = findPreviousReducerSuffix(word);
717 if (usePreviousSuffix.first)
718 {
719 // here, we use a multiple of a previously reduced row
720 Word tmpWord;
721 if (word.size() != 0)
722 tmpWord.init(word.begin(), word.begin() + 1);
723 return std::make_pair(true, PreRow {tmpWord,
724 usePreviousSuffix.second,
725 Word(),
727 }
728 auto usePreviousPrefix = findPreviousReducerPrefix(word);
729 if (usePreviousPrefix.first)
730 {
731 // here, we use a multiple of a previously reduced row
732 Word tmpWord;
733 if (word.size() != 0)
734 tmpWord.init(word.end()-1, word.end());
735 return std::make_pair(true, PreRow {Word(),
736 usePreviousPrefix.second,
737 tmpWord,
739 }
740
741 // if we are here, then the Monom does not have a prefix/suffix
742 // that was processed previously.
743
744 // look in mWordTable for Monom
745 std::pair<int,int> divisorInfo;
746
747 // TODO: for certain inputs (e.g. Monoms that we *know* are of
748 // the form xm or mx for m a standard monomial and x a
749 // variable, one needs only to check prefixes or
750 // suffixes, not all subwords. Not sure how to utilize that
751 // just yet.
752
753 bool found = mWordTable.subword(word, divisorInfo);
754
755 // if newword = x^a x^b x^c, with x^b in the word table, then:
756 // divisorInfo.first = index of the GB element with x^b as lead monomial.
757 // divisorInfo.second = position of the start of x^b in newword
758 // (that is, the length of x^a).
759 if (not found)
760 return std::make_pair(false, PreRow {Word(), 0, Word(), ReducerPreRow});
761 // if found, then return this information to caller
762 Word prefix = Word(word.begin(), word.begin() + divisorInfo.second);
763 Word divisorWord = mWordTable[divisorInfo.first];
764 Word suffix = Word(word.begin() + divisorInfo.second + divisorWord.size(),
765 word.end());
766 return std::make_pair(true, PreRow {prefix, divisorInfo.first, suffix, ReducerPreRow});
767}
768
769std::pair<bool,int> NCF4::findPreviousReducerPrefix(const Word& w)
770{
771 // build the largest proper prefix of m and look it up in previous
772 // mColumnMonomials table. we will return (true, row index) if
773 // found and (false, -1) if not.
774
775 // note that just because the second coordinate of an
776 // mColumnMonomials entry is -1 does not mean there isn't a reducer
777 // in the row -- in this case it is a new GB element and already
778 // added to the mGroebner list. In this case, we will be using that
779 // entry anyway so no need to make the additional effort to find it
780 // in the mRows table.
781
782 // get prefix of m as a monom
783 // search for prefix in mPreviousColumnMonomials
784 // if it.second.second != -1, then return (true,it.second.first)
785 // else return (false, -1)
786
787 // if the monom is the empty monomial, return false
788 if (w.size() == 0) return std::make_pair(false,-1);
789
790 std::pair<bool,int> retval;
791
792 Word prefix(w.begin(),w.end()-1);
793 const auto it = mPreviousColumnMonomials.find(prefix);
794 if (it == mPreviousColumnMonomials.end()) // not in table
795 retval = std::make_pair(false,-1);
796 else
797 {
798 int colNum = (*it).second.first;
799 if (mPreviousColumns[colNum].pivotRow == -1) // in column table and not a reducer monomial
800 retval = std::make_pair(false,-1);
801 else // in table and a reducer monomial
802 retval = std::make_pair(true,mPreviousColumns[colNum].pivotRow);
803 }
804 return retval;
805}
806
807
808std::pair<bool,int> NCF4::findPreviousReducerSuffix(const Word& w)
809{
810 // basically the same as above, except with suffixes
811
812 // get suffix of m
813 // search for suffix in mPreviousColumnMonomials
814 // if it.second.second != -1, then return (true,it.second.first)
815 // else return (false, -1)
816 if (w.size() == 0) return std::make_pair(false,-1);
817
818 std::pair<bool,int> retval;
819
820 Word suffix(w.begin()+1,w.end());
821 const auto it = mPreviousColumnMonomials.find(suffix);
822 if (it == mPreviousColumnMonomials.end()) //not in table
823 retval = std::make_pair(false,-1);
824 else
825 {
826 int colNum = (*it).second.first;
827 if (mPreviousColumns[colNum].pivotRow == -1) // in column table and not a reducer monomial
828 retval = std::make_pair(false,-1);
829 else // in table and a reducer monomial
830 retval = std::make_pair(true,mPreviousColumns[colNum].pivotRow);
831 }
832 return retval;
833}
834
835// Besides sorting the columns (using 'perm'), this also sets the
836// pivot rows of each column index (in the new sorted order).
838{
839 size_t sz = mColumnMonomials.size();
840 std::vector<int> columnIndices;
841 std::vector<Word> tempWords;
842
843 tempWords.reserve(sz);
844 columnIndices.resize(sz);
845 std::iota(columnIndices.begin(), columnIndices.end(), 0);
846
847 // store all the column monomials in a temporary to sort them
848 // and also set the reducer column for them on the same pass
849 for (auto& i : mColumnMonomials)
850 tempWords.emplace_back(i.first);
851
852 // create the monomial sorter object
853 MonomSort<std::vector<Word>> monomialSorter(&freeAlgebra().monoid(),&tempWords);
854 // stable sort was here before, but this sort is based on a total ordering
855 // with no ties so we can use an unstable (and hence parallel!) sort.
856 if (mIsParallel)
857 mtbb::parallel_sort(columnIndices.begin(),columnIndices.end(),monomialSorter);
858 else
859 std::stable_sort(columnIndices.begin(),columnIndices.end(),monomialSorter);
860
861 auto applyLabelingColumns = [&](const mtbb::blocked_range<int>& r) {
862 for (auto count = r.begin(); count != r.end(); ++count)
863 {
864 auto& val = mColumnMonomials[tempWords[columnIndices[count]]];
865 val.first = count;
866 mColumns[count].word = tempWords[columnIndices[count]];
867 mColumns[count].pivotRow = -1;
868 }
869 };
870
871 // apply the sorted labeling to the columns
872 mColumns.resize(sz);
873 if (mIsParallel)
874 mtbb::parallel_for(mtbb::blocked_range<int>{0,(int)sz}, applyLabelingColumns);
875 else
876 applyLabelingColumns(mtbb::blocked_range<int>{0,(int)sz});
877
878 auto applyLabelingRows = [&](const mtbb::blocked_range<int>& r) {
879 for (auto i = r.begin(); i != r.end(); ++i)
880 {
881 auto& comps = mRows[i].columnIndices;
882 auto& words = mRows[i].columnWords;
883 // sets the pivot row in the column if this is a reducer row
884 if (i < mFirstOverlap)
885 {
886 mColumns[mColumnMonomials[words[0]].first].pivotRow = i;
887 mColumnMonomials[words[0]].second = i;
888 }
889 for (int j = 0; j < words.size(); ++j)
890 comps[j] = mColumnMonomials[words[j]].first;
891 }
892 };
893
894 // now fix the column labels in the rows and set pivot rows in columns
895 if (mIsParallel)
896 mtbb::parallel_for(mtbb::blocked_range<int>{0,(int)mRows.size()},applyLabelingRows);
897 else
898 applyLabelingRows(mtbb::blocked_range<int>{0,(int)mRows.size()});
899}
900
901// both reduceF4Row and parallelReduceF4Row call this function
902// with the appropriate mutexes inserted for lock.
903// reduceF4Row: tbb::null_mutex (a do-nothing mutex)
904// parallelReduceF4Row: tbb::queuing_mutex (for now)
905template<typename LockType>
907 int first,
908 int firstcol,
909 NCF4Stats &ncF4Stats,
910 ElementArray& dense,
911 bool updateColumnIndex,
912 LockType& lock)
913{
914 int sz = mRows[index].columnIndices.size();
915 //assert(sz > 0); this may be zero when autoreducing the new gb elements
916 if (sz == 0) return;
917 if (sz == 1 && firstcol != -1) return;
918
919 int last = mRows[index].columnIndices[sz-1];
920
921 mVectorArithmetic->fillDenseArray(dense,
922 mRows[index].coeffVector,
923 mRows[index].columnIndices);
924
925 do {
926 int pivotrow = mColumns[first].pivotRow;
927 if (pivotrow >= 0)
928 {
929 ncF4Stats.numCancellations++;
930 mVectorArithmetic->denseCancelFromSparse(dense,
931 mRows[pivotrow].coeffVector,
932 mRows[pivotrow].columnIndices);
933 // last component in the row corresponding to pivotrow
934 int last1 = mRows[pivotrow].columnIndices.cend()[-1];
935 last = (last1 > last ? last1 : last);
936 }
937 else if (firstcol == -1)
938 {
939 firstcol = first;
940 }
941 first = mVectorArithmetic->denseNextNonzero(dense, first+1, last);
942 } while (first <= last);
943
944 // we have to free mRows[index] information because we are about to overwrite it
945 // how can I free mRows[index].columnIndices? it wasn't the last block allocated on mMonomialSpace...
946 mVectorArithmetic->safeDenseToSparse(dense,
947 mRows[index].coeffVector,
948 mRows[index].columnIndices,
949 firstcol,
950 last,
952 lock);
953 if (mVectorArithmetic->size(mRows[index].coeffVector) > 0)
954 {
955 mVectorArithmetic->makeMonic(mRows[index].coeffVector);
956 // don't do this in the parallel version
957 if (updateColumnIndex) mColumns[firstcol].pivotRow = index;
958 }
959}
960
962{
963 NCF4Stats ncF4Stats;
964 using threadLocalDense_t = mtbb::enumerable_thread_specific<ElementArray>;
965 using threadLocalStats_t = mtbb::enumerable_thread_specific<NCF4Stats>;
966
967 // create a dense array for each thread
968 threadLocalDense_t threadLocalDense([&]() {
969 return mVectorArithmetic->allocateElementArray(mColumnMonomials.size());
970 });
971 auto denseVector = mVectorArithmetic->allocateElementArray(mColumnMonomials.size());
972
973 threadLocalStats_t threadLocalStats([&]() {
974 return NCF4Stats();
975 });
976
977 // access the number of allowable threads this way.
978 //std::cout << "M2 Number of Threads: " << getAllowableThreads() << std::endl;
979
980 // reduce each overlap row by mRows.
981
982 mtbb::queuing_mutex lock;
983 mtbb::parallel_for(mtbb::blocked_range<int>{mFirstOverlap,(int)mRows.size()},
984 [&](const mtbb::blocked_range<int>& r)
985 {
986 threadLocalDense_t::reference my_dense = threadLocalDense.local();
987 threadLocalStats_t::reference my_threadStats = threadLocalStats.local();
988 for (auto i = r.begin(); i != r.end(); ++i) {
990 mRows[i].columnIndices[0],
991 -1,
992 my_threadStats,
993 my_dense,
994 lock);
995 my_threadStats.numRows++;
996 }
997 });
998
999 int numThreads = 0;
1000 for (auto tlStats : threadLocalStats)
1001 {
1002 ++numThreads;
1003 if (M2_gbTrace >= 2)
1004 {
1005 std::cout << "numCancellations for this thread: " << tlStats.numCancellations << std::endl;
1006 std::cout << "numRows for this thread: " << tlStats.numRows << std::endl;
1007 }
1008 ncF4Stats.numCancellations += tlStats.numCancellations;
1009 }
1010
1011 // sequentially perform one more pass to reduce the spair rows down
1012 for (auto i = mFirstOverlap; i < mRows.size(); ++i)
1013 reduceF4Row(i,
1014 mRows[i].columnIndices[0],
1015 -1,
1016 ncF4Stats,
1017 denseVector);
1018
1019 // interreduce the matrix with respect to these overlaps.
1020 // This needs to be sequential as well
1021 for (auto i = mRows.size(); i > mFirstOverlap; --i)
1022 reduceF4Row(i-1,
1023 mRows[i-1].columnIndices[1],
1024 mRows[i-1].columnIndices[0],
1025 ncF4Stats,
1026 denseVector);
1027
1028 for (auto tlDense : threadLocalDense)
1029 mVectorArithmetic->deallocateElementArray(tlDense);
1030
1031 mVectorArithmetic->deallocateElementArray(denseVector);
1032 if (M2_gbTrace >= 2)
1033 {
1034 std::cout << "Number of cancellations: " << ncF4Stats.numCancellations << std::endl;
1035 std::cout << "Number of threads used: " << numThreads << std::endl;
1036 }
1037}
1038
1040{
1041 NCF4Stats ncF4Stats;
1042
1043 auto denseVector = mVectorArithmetic->allocateElementArray(mColumnMonomials.size());
1044
1045 // reduce each overlap row by mRows.
1046 for (auto i = mFirstOverlap; i < mRows.size(); ++i)
1047 reduceF4Row(i,
1048 mRows[i].columnIndices[0],
1049 -1,
1050 ncF4Stats,
1051 denseVector);
1052
1053 // interreduce the matrix with respect to these overlaps.
1054 for (auto i = mRows.size(); i > mFirstOverlap; --i)
1055 reduceF4Row(i-1,
1056 mRows[i-1].columnIndices[1],
1057 mRows[i-1].columnIndices[0],
1058 ncF4Stats,
1059 denseVector);
1060
1061 mVectorArithmetic->deallocateElementArray(denseVector);
1062
1063 //std::cout << "Number of cancellations: " << ncF4Stats.numCancellations << std::endl;
1064}
1065
1066void NCF4::displayF4MatrixSize(std::ostream & o) const
1067{
1068 // Display sizes:
1069 o << "(#cols, #reducer rows, #spair rows) = ("
1070 << mColumnMonomials.size() << ", "
1071 << mFirstOverlap << ", "
1072 << mRows.size() - mFirstOverlap << ")"
1073 << " ";
1074 long numReducerEntries = 0;
1075 long numSPairEntries = 0;
1076
1077 // if (mRows.size() != mReducersTodo.size())
1078 // {
1079 // o << std::endl;
1080 // o << "***ERROR*** expected mRows and mReducersTodo to have the same length!" << std::endl;
1081 // o << " mRows size: " << mRows.size() << std::endl;
1082 // o << "mReducersTodo size: " << mReducersTodo.size() << std::endl;
1083 // exit(1);
1084 // }
1085 for (auto i = 0; i < mRows.size(); ++i)
1086 {
1087 if (i < mFirstOverlap)
1088 numReducerEntries += mVectorArithmetic->size(mRows[i].coeffVector);
1089 else
1090 numSPairEntries += mVectorArithmetic->size(mRows[i].coeffVector);
1091 if (mVectorArithmetic->size(mRows[i].coeffVector) != mRows[i].columnIndices.size())
1092 o << "***ERROR*** ring_elem and component ranges do not match!" << std::endl;
1093 }
1094 o << "#entries: (" << numReducerEntries << "," << numSPairEntries << ")"
1095 << std::endl;
1096}
1097
1098void NCF4::displayF4Matrix(std::ostream& o) const
1099{
1101 // Now column monomials
1102 for (auto i : mColumnMonomials)
1103 {
1104 // each i is a pair (const Monom, pair(int,int)).
1105 buffer b;
1106 FreeMonoid::MonomialInserter monomInserter;
1107 freeAlgebra().monoid().monomInsertFromWord(monomInserter,i.first);
1108 Monom m(monomInserter.data());
1110 o << b.str() << "(" << i.second.first << ", " << i.second.second << ") ";
1111 if (i.second.second != -1 and
1112 (mRows[i.second.second].columnIndices.begin() == nullptr or
1113 mRows[i.second.second].columnIndices[0] != i.second.first))
1114 {
1115 std::cout << "Oops (" << mRows[i.second.second].columnIndices.begin()
1116 << "," << mRows[i.second.second].columnIndices[0] << ","
1117 << i.second.first << ")";
1118 }
1119 }
1120 o << std::endl;
1121
1122 // For each row, and each overlap row, display the non-zero comps, non-zero coeffs.
1123 // if (mRows.size() != mReducersTodo.size())
1124 // {
1125 // o << std::endl;
1126 // o << "***ERROR*** expected mRows and mReducersTodo to have the same length!" << std::endl;
1127 // o << " mRows size: " << mRows.size() << std::endl;
1128 // o << "mReducersTodo size: " << mReducersTodo.size() << std::endl;
1129 // exit(1);
1130 // }
1131 const Ring* kk = freeAlgebra().coefficientRing();
1132 for (auto count = 0; count < mRows.size(); ++count)
1133 {
1134 // PreRow pr = mReducersTodo[count];
1135 // o << count << " ("<< std::get<0>(pr) << ", "
1136 // << std::get<1>(pr) << ", "
1137 // << std::get<2>(pr) << ", "
1138 // << std::get<3>(pr) << ") "
1139 if (mRows[count].columnIndices.begin() == nullptr)
1140 {
1141 o << "Row " << count
1142 << " is empty. This may indicate an error depending on the current state."
1143 << std::endl;
1144 continue;
1145 }
1146 o << "Row " << count << ";" << mRows[count].columnIndices.size() << ": ";
1147 if (mVectorArithmetic->size(mRows[count].coeffVector) != mRows[count].columnIndices.size())
1148 {
1149 o << "***ERROR*** expected coefficient array and components array to have the same length" << std::endl;
1150 exit(1);
1151 }
1152 for (auto i=0; i < mVectorArithmetic->size(mRows[count].coeffVector); ++i)
1153 {
1154 buffer b;
1155 kk->elem_text_out(b, mVectorArithmetic->ringElemFromElementArray(mRows[count].coeffVector,i));
1156 o << "[" << mRows[count].columnIndices[i] << "," << b.str() << "] ";
1157 }
1158 o << std::endl;
1159 }
1160}
1161
1162void NCF4::displayFullF4Matrix(std::ostream& o) const
1163{
1165 // Now column monomials
1166 for (auto i : mColumnMonomials)
1167 {
1168 buffer b;
1169 FreeMonoid::MonomialInserter monomInserter;
1170 freeAlgebra().monoid().monomInsertFromWord(monomInserter,i.first);
1171 Monom m(monomInserter.data());
1173 o << b.str() << "(" << i.second.first << ", " << i.second.second << ") ";
1174 // each i is a pair (const Monom, pair(int,int)).
1175 }
1176 o << std::endl;
1177 // For each row, and each overlap row, display the non-zero comps, non-zero coeffs.
1178 if (mRows.size() != mReducersTodo.size())
1179 {
1180 o << "***ERROR*** expected mRows and mReducersTodo to have the same length!" << std::endl;
1181 exit(1);
1182 }
1183 const Ring* kk = freeAlgebra().coefficientRing();
1184 for (auto count = 0; count < mRows.size(); ++count)
1185 {
1186 PreRow pr = mReducersTodo[count];
1187 o << count << " ("<< pr.left << ", "
1188 << pr.preRowIndex << ", "
1189 << pr.right << ")";
1190 size_t count2 = 0;
1191 for (auto i=0; i < mColumnMonomials.size(); i++)
1192 {
1193 if (count2 == mVectorArithmetic->size(mRows[count].coeffVector) or
1194 mRows[count].columnIndices[count2] != i)
1195 {
1196 o << " 0 ";
1197 }
1198 else
1199 {
1200 buffer b;
1201 kk->elem_text_out(b,mVectorArithmetic->ringElemFromElementArray(mRows[count].coeffVector,count2));
1202 o << " " << b.str() << " ";
1203 count2++;
1204 }
1205 }
1206 o << std::endl;
1207 }
1208}
1209
1211{
1212 for (auto r : rowsVector)
1213 {
1214 // the VectorArithmetic object calls clear() on the ring elements in r.coeffVector as well.
1215 mVectorArithmetic->deallocateElementArray(r.coeffVector);
1216 }
1217 rowsVector.clear();
1218}
1219
1220// Local Variables:
1221// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
1222// indent-tabs-mode: nil
1223// End:
Free associative algebra k<x_1,...,x_n> over an arbitrary coefficient ring.
NCF4 — non-commutative F4 Gröbner-basis driver building a per-degree Macaulay matrix.
std::vector< int > word
std::tuple< int, int, int, bool > Overlap
OverlapTable — degree-sorted queue of pending word overlaps for non-commutative GB drivers.
gc_vector< const Poly * > ConstPolyList
Polynomial< CoefficientRingType > Poly
gc_vector< Poly * > PolyList
Word prefix(const Word vec, int lengthOfPrefix)
Word suffix(const Word vec, int indexOfSuffix)
Coefficient-ring-erased arithmetic dispatcher used by F4, GB, and resolution code.
WordTable / WordWithDataTable — leading-word indices for non-commutative Gröbner basis lookup.
Append-only GC-backed byte buffer used throughout the engine for text output.
Type-erased owning handle to a dense coefficient vector held by a ConcreteVectorArithmetic<Ring>.
const Ring * coefficientRing() const
std::pair< int, bool > heft_degree(const Poly &f) const
void subtractScalarMultipleOf(Poly &result, const Poly &f, const Poly &g, ring_elem coeff) const
Word lead_word(const Poly &f) const
const FreeMonoid & monoid() const
void swap(Poly &f, Poly &g) const
Free associative algebra over a coefficient ring: the non-commutative analogue of PolynomialRing.
gc_vector< int > MonomialInserter
Word wordProductAsWord(const Word &left, const Word &right, MemoryBlock &memBlock) const
void monomInsertFromWord(MonomialInserter &result, const Word &w) const
void elem_text_out(buffer &o, const Monom &m1) const
void wordFromMonom(Word &result, const Monom &m) const
std::pair< T *, T * > allocateArray(size_t nelems)
Thin RAII wrapper around memtailor::Arena providing bump-pointer array allocation with optional mutex...
void process(const std::deque< Overlap > &overlapsToProcess)
Definition NCF4.cpp:89
MonomEq mMonomEq
Definition NCF4.hpp:231
PolyList mGroebner
Definition NCF4.hpp:222
NCF4(const FreeAlgebra &A, const ConstPolyList &input, int hardDegreeLimit, int strategy, int numThreads)
Definition NCF4.cpp:19
auto overlapHeft(Overlap o) const -> int
Definition NCF4.cpp:222
void reduceF4Row(int index, int first, int firstcol, NCF4Stats &ncF4Stats, ElementArray &dense)
Definition NCF4.hpp:357
void displayF4Matrix(std::ostream &o) const
Definition NCF4.cpp:1098
MemoryBlock mPreviousMonomialSpace
Definition NCF4.hpp:229
auto isOverlapNecessary(const Overlap &o) -> bool
Definition NCF4.cpp:251
ColumnsVector mPreviousColumns
Definition NCF4.hpp:241
bool mIsGraded
Definition NCF4.hpp:224
void parallelReduceF4Matrix()
Definition NCF4.cpp:961
MonomHash mMonomHash
Definition NCF4.hpp:233
void parallelReduceF4Row(int index, int first, int firstcol, NCF4Stats &ncF4Stats, ElementArray &dense, mtbb::queuing_mutex &lock)
Definition NCF4.hpp:373
const ConstPolyList mInput
Definition NCF4.hpp:217
mtbb::feeder< PreRow > PreRowFeeder
Definition NCF4.hpp:190
void parallelBuildF4Matrix(const std::deque< Overlap > &overlapsToProcess)
Definition NCF4.cpp:510
void generalReduceF4Row(int index, int first, int firstcol, NCF4Stats &ncF4Stats, ElementArray &dense, bool updateColumnIndex, LockType &lock)
Definition NCF4.cpp:906
RowsVector mPreviousRows
Definition NCF4.hpp:244
void addToGroebnerBasis(Poly *toAdd)
Definition NCF4.cpp:193
ring_elem getCoeffOfMonom(const Poly &f, const Monom &m) const
Definition NCF4.cpp:347
void clearRows(RowsVector &rowsVector)
Definition NCF4.cpp:1210
mtbb::queuing_mutex mColumnMutex
Definition NCF4.hpp:262
std::vector< MemoryBlock * > mMemoryBlocks
Definition NCF4.hpp:260
void reduceF4Matrix()
Definition NCF4.cpp:1039
void updateOverlaps(const Poly *toAdd)
Definition NCF4.cpp:198
void matrixReset()
Definition NCF4.cpp:375
PreRowType
Definition NCF4.hpp:121
@ OverlapPreRow
Definition NCF4.hpp:121
@ ReducerPreRow
Definition NCF4.hpp:121
@ PreviousReducerPreRow
Definition NCF4.hpp:121
void processPreviousF4Matrix()
Definition NCF4.cpp:159
std::vector< PreRow > mOverlapsTodo
Definition NCF4.hpp:239
MonomHashEqual mMonomHashEqual
Definition NCF4.hpp:232
PolyList newGBelements() const
Definition NCF4.cpp:315
void reducedRowToPoly(Poly *result, const RowsVector &rows, const ColumnsVector &cols, int i) const
Definition NCF4.cpp:328
void processPreRow(PreRow r, RowsVector &rowsVector, MemoryBlock &memoryBlock, PreRowFeeder *feeder)
Definition NCF4.cpp:583
std::vector< Row, gc_allocator< Row > > RowsVector
Definition NCF4.hpp:187
MonomialHash mColumnMonomials
Definition NCF4.hpp:235
void preRowsFromOverlap(const Overlap &o)
Definition NCF4.cpp:393
const FreeAlgebra & mFreeAlgebra
Definition NCF4.hpp:216
std::pair< bool, int > findPreviousReducerSuffix(const Word &w)
Definition NCF4.cpp:808
int mFirstOverlap
Definition NCF4.hpp:247
std::vector< MemoryBlock * > mPreviousMemoryBlocks
Definition NCF4.hpp:261
bool mIsParallel
Definition NCF4.hpp:253
void processWordInPreRow(Word &w, PreRowFeeder *feeder)
Definition NCF4.cpp:678
void displayFullF4Matrix(std::ostream &o) const
Definition NCF4.cpp:1162
RowsVector mRows
Definition NCF4.hpp:243
std::pair< bool, PreRow > findDivisor(Word w)
Definition NCF4.cpp:710
Word createOverlapLeadWord(const Overlap &o)
Definition NCF4.cpp:301
void displayF4MatrixSize(std::ostream &o) const
Definition NCF4.cpp:1066
auto checkOldOverlaps(Word &newLeadWord) -> void
Definition NCF4.cpp:267
WordTable mWordTable
Definition NCF4.hpp:219
MemoryBlock mMonomialSpace
Definition NCF4.hpp:228
std::vector< PreRow > mReducersTodo
Definition NCF4.hpp:238
void labelAndSortF4Matrix()
Definition NCF4.cpp:837
int mNumThreads
Definition NCF4.hpp:252
const VectorArithmetic * mVectorArithmetic
Definition NCF4.hpp:250
std::vector< Column > ColumnsVector
Definition NCF4.hpp:184
void compute(int softDegreeLimit)
Definition NCF4.cpp:67
std::pair< bool, int > findPreviousReducerPrefix(const Word &w)
Definition NCF4.cpp:769
auto insertNewOverlaps(std::vector< Overlap > &newOverlaps) -> void
Definition NCF4.cpp:235
RowsVector mOverlaps
Definition NCF4.hpp:245
mtbb::task_arena mScheduler
Definition NCF4.hpp:255
ColumnsVector mColumns
Definition NCF4.hpp:240
void buildF4Matrix(const std::deque< Overlap > &overlapsToProcess)
Definition NCF4.cpp:468
OverlapTable mOverlapTable
Definition NCF4.hpp:221
const FreeAlgebra & freeAlgebra() const
Definition NCF4.hpp:282
void autoreduceByLastElement()
Definition NCF4.cpp:358
MonomialHash mPreviousColumnMonomials
Definition NCF4.hpp:236
ring_elem zero() const
Definition ring.hpp:359
virtual void elem_text_out(buffer &o, const ring_elem f, bool p_one=true, bool p_plus=false, bool p_parens=false) const =0
xxx xxx xxx
Definition ring.hpp:102
Runtime dispatcher that hides the concrete coefficient ring behind a std::variant of ConcreteVectorAr...
const int * begin() const
Definition Word.hpp:72
void init(const int *begin, const int *end)
Definition Word.hpp:68
const int * end() const
Definition Word.hpp:73
int size() const
Definition Word.hpp:74
Non-owning view of a non-commutative word: [begin, end) of int variable indices.
Definition Word.hpp:56
static void subwordPositions(Word word1, Word word2, std::vector< int > &result_start_indices)
Definition WordTable.cpp:38
int size()
Definition buffer.hpp:70
char * str()
Definition buffer.hpp:72
int p
VALGRIND_MAKE_MEM_DEFINED & result(result)
char newline[]
Definition m2-types.cpp:49
int M2_gbTrace
Definition m2-types.cpp:52
Engine-to-interpreter type vocabulary across the C++ / .dd boundary.
Ring — the legacy abstract base class for every coefficient and polynomial ring.
TermIterator< Nterm > begin(Nterm *ptr)
Definition ringelem.cpp:4
ring_elem — the universal value type carried by every Ring* in the engine.
Non-owning view onto a [length, degree, v1, v2, ..., vn] packed monomial in some externally managed b...
long numCancellations
Definition NCF4.hpp:211
Per-thread counters tracking how much work the F4 reduction did.
Definition NCF4.hpp:209
Word left
Definition NCF4.hpp:139
int preRowIndex
Definition NCF4.hpp:140
Word right
Definition NCF4.hpp:141
PreRowType preRowType
Definition NCF4.hpp:142
Symbolic description of one row before it is materialised in the matrix: a left * (something) * right...
Definition NCF4.hpp:138
A materialised row of the Macaulay matrix: parallel coefficient and monomial arrays.
Definition NCF4.hpp:158
void emit_wrapped(const char *s)
Definition text-io.cpp:27
void emit(const char *s)
Definition text-io.cpp:41
Text-formatting helpers layered on buffer: bignum print, line wrapping, M2_gbTrace-gated emit.
double seconds(DurationType time_diff)
Definition timing.hpp:59