12#include "../system/supervisorinterface.h"
39 (void) hardDegreeLimit;
50 for (
int i = 0; i <
mInput.size(); ++i)
57 std::make_tuple(i,-1,-1,
true));
62 o << (
mIsGraded ?
" homogeneous " :
" inhomogeneous ");
72 auto toBeProcessed = degSet.second;
76 o <<
"{" << degSet.first <<
"}(" << toBeProcessed->
size() <<
")";
95 o <<
newline <<
"F4 processing: # overlaps (spairs): " << overlapsToProcess.size() <<
newline;
101 mtbb::tick_count t0 = mtbb::tick_count::now();
106 mtbb::tick_count t1 = mtbb::tick_count::now();
108 std::cout <<
"Time spent on build step: " << (t1-t0).
seconds() << std::endl;
112 std::cout <<
"NC F4 GB: matrix size: ";
123 t0 = mtbb::tick_count::now();
128 t1 = mtbb::tick_count::now();
130 std::cout <<
"Time spent on reduction step: " << (t1-t0).
seconds() << std::endl;
138 for (
auto& f : newElems)
151 o <<
"F4 processing: # GB added: " << newElems.size() <<
newline;
164 if (
mRows[i].columnIndices.size() == 0)
continue;
165 int newReducerCol =
mRows[i].columnIndices[0];
166 mColumns[newReducerCol].pivotRow = i;
200 std::vector<Overlap> newLeftOverlaps;
201 std::vector<Overlap> newRightOverlaps;
206 mWordTable.insert(newLeadWord,newRightOverlaps);
230 int len_of_s = tmpL.
size() - std::get<1>(o);
237 for (
auto newOverlap : newOverlaps)
242 std::cout <<
"Reduction avoided using eager 2nd criterion." << std::endl;
263 retval = !
mWordTable.isNontrivialSuperword(w, std::get<0>(o), std::get<2>(o));
273 std::vector<int> startIndices;
277 for (
auto& o :
p.second)
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();
287 for (
auto j : startIndices)
289 if (j != 0 or j != w.size() - newLeadWord.size())
292 std::cout <<
"Reduction avoided using lazy 2nd criterion." << std::endl;
293 std::get<3>(o) =
false;
308 int sz = left.
size() + right.
size();
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);
320 if (
mRows[i].columnIndices.size() == 0)
continue;
336 auto& resultCoeffInserter =
result->getCoeffInserter();
337 auto& resultMonomInserter =
result->getMonomInserter();
340 using ContainerType =
decltype(resultCoeffInserter);
341 mVectorArithmetic->appendToContainer<ContainerType>(rows[i].coeffVector,resultCoeffInserter);
343 for (
const auto& col : rows[i].columnIndices)
349 for (
auto t = f.cbegin(); t != f.cend(); ++t)
362 Monom leadMon = lastPoly.cbegin().monom();
366 if (!
freeAlgebra().coefficientRing()->is_zero(foundCoeff))
400 int gbLeftIndex = std::get<0>(o);
401 int overlapPos = std::get<1>(o);
402 int gbRightIndex = std::get<2>(o);
422 int overlapLen = leadWordLeft.
size() - overlapPos;
425 Word prefix2(leadWordLeft.
begin(), leadWordLeft.
begin() + overlapPos);
427 Word suffix1(leadWordRight.
begin() + overlapLen, leadWordRight.
end());
444 if (gbLeftIndex > gbRightIndex)
474 for (
auto o : overlapsToProcess)
476 auto stillValid = std::get<3>(o);
494 for (
int i=numReducersAtFirst ; i <
mReducersTodo.size(); ++i)
516 for (
auto o : overlapsToProcess)
518 auto stillValid = std::get<3>(o);
527 mtbb::enumerable_thread_specific<ThreadData> threadData([&](){
528 mtbb::queuing_mutex::scoped_lock myColumnLock(
mColumnMutex);
542 auto& data = threadData.local();
543 processPreRow(prerow,
550 for (
const auto& data : threadData)
552 mRows.reserve(
mRows.size() + data.rowsVector.size());
553 std::move(data.rowsVector.begin(),
554 data.rowsVector.end(),
555 std::back_inserter(
mRows));
571 for (
int i=numReducersAtFirst ; i <
mReducersTodo.size(); ++i)
596 std::cout <<
"Processing PreRow: ("
597 << left <<
"," << gbIndex <<
"," << right <<
")"
619 elem =
mInput[-gbIndex-1];
635 int numTerms = elem->numTerms();
643 Word* nextColWord = wordRange.first;
645 for (
auto i = elem->cbegin(); i != elem->cend(); ++i)
666 rowsVector.emplace_back(
Row {coeffs, columnRange, wordRange});
702 if (feeder ==
nullptr)
705 feeder->add(divresult.second);
717 if (usePreviousSuffix.first)
721 if (
word.size() != 0)
723 return std::make_pair(
true,
PreRow {tmpWord,
724 usePreviousSuffix.second,
729 if (usePreviousPrefix.first)
733 if (
word.size() != 0)
736 usePreviousPrefix.second,
745 std::pair<int,int> divisorInfo;
788 if (w.
size() == 0)
return std::make_pair(
false,-1);
790 std::pair<bool,int> retval;
795 retval = std::make_pair(
false,-1);
798 int colNum = (*it).second.first;
800 retval = std::make_pair(
false,-1);
816 if (w.
size() == 0)
return std::make_pair(
false,-1);
818 std::pair<bool,int> retval;
823 retval = std::make_pair(
false,-1);
826 int colNum = (*it).second.first;
828 retval = std::make_pair(
false,-1);
840 std::vector<int> columnIndices;
841 std::vector<Word> tempWords;
843 tempWords.reserve(sz);
844 columnIndices.resize(sz);
845 std::iota(columnIndices.begin(), columnIndices.end(), 0);
850 tempWords.emplace_back(i.first);
857 mtbb::parallel_sort(columnIndices.begin(),columnIndices.end(),monomialSorter);
859 std::stable_sort(columnIndices.begin(),columnIndices.end(),monomialSorter);
861 auto applyLabelingColumns = [&](
const mtbb::blocked_range<int>& r) {
862 for (
auto count = r.begin(); count != r.end(); ++count)
866 mColumns[count].word = tempWords[columnIndices[count]];
874 mtbb::parallel_for(mtbb::blocked_range<int>{0,(
int)sz}, applyLabelingColumns);
876 applyLabelingColumns(mtbb::blocked_range<int>{0,(
int)sz});
878 auto applyLabelingRows = [&](
const mtbb::blocked_range<int>& r) {
879 for (
auto i = r.begin(); i != r.end(); ++i)
881 auto& comps =
mRows[i].columnIndices;
882 auto& words =
mRows[i].columnWords;
889 for (
int j = 0; j < words.size(); ++j)
896 mtbb::parallel_for(mtbb::blocked_range<int>{0,(
int)
mRows.size()},applyLabelingRows);
898 applyLabelingRows(mtbb::blocked_range<int>{0,(
int)
mRows.size()});
905template<
typename LockType>
911 bool updateColumnIndex,
914 int sz =
mRows[index].columnIndices.size();
917 if (sz == 1 && firstcol != -1)
return;
919 int last =
mRows[index].columnIndices[sz-1];
922 mRows[index].coeffVector,
923 mRows[index].columnIndices);
926 int pivotrow =
mColumns[first].pivotRow;
931 mRows[pivotrow].coeffVector,
932 mRows[pivotrow].columnIndices);
934 int last1 =
mRows[pivotrow].columnIndices.cend()[-1];
935 last = (last1 > last ? last1 : last);
937 else if (firstcol == -1)
942 }
while (first <= last);
947 mRows[index].coeffVector,
948 mRows[index].columnIndices,
957 if (updateColumnIndex)
mColumns[firstcol].pivotRow = index;
964 using threadLocalDense_t = mtbb::enumerable_thread_specific<ElementArray>;
965 using threadLocalStats_t = mtbb::enumerable_thread_specific<NCF4Stats>;
968 threadLocalDense_t threadLocalDense([&]() {
973 threadLocalStats_t threadLocalStats([&]() {
982 mtbb::queuing_mutex lock;
984 [&](
const mtbb::blocked_range<int>& r)
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],
995 my_threadStats.numRows++;
1000 for (
auto tlStats : threadLocalStats)
1005 std::cout <<
"numCancellations for this thread: " << tlStats.numCancellations << std::endl;
1006 std::cout <<
"numRows for this thread: " << tlStats.numRows << std::endl;
1014 mRows[i].columnIndices[0],
1023 mRows[i-1].columnIndices[1],
1024 mRows[i-1].columnIndices[0],
1028 for (
auto tlDense : threadLocalDense)
1034 std::cout <<
"Number of cancellations: " << ncF4Stats.
numCancellations << std::endl;
1035 std::cout <<
"Number of threads used: " << numThreads << std::endl;
1048 mRows[i].columnIndices[0],
1056 mRows[i-1].columnIndices[1],
1057 mRows[i-1].columnIndices[0],
1069 o <<
"(#cols, #reducer rows, #spair rows) = ("
1074 long numReducerEntries = 0;
1075 long numSPairEntries = 0;
1085 for (
auto i = 0; i <
mRows.size(); ++i)
1092 o <<
"***ERROR*** ring_elem and component ranges do not match!" << std::endl;
1094 o <<
"#entries: (" << numReducerEntries <<
"," << numSPairEntries <<
")"
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))
1115 std::cout <<
"Oops (" <<
mRows[i.second.second].columnIndices.begin()
1116 <<
"," <<
mRows[i.second.second].columnIndices[0] <<
","
1117 << i.second.first <<
")";
1132 for (
auto count = 0; count <
mRows.size(); ++count)
1139 if (
mRows[count].columnIndices.begin() ==
nullptr)
1141 o <<
"Row " << count
1142 <<
" is empty. This may indicate an error depending on the current state."
1146 o <<
"Row " << count <<
";" <<
mRows[count].columnIndices.size() <<
": ";
1149 o <<
"***ERROR*** expected coefficient array and components array to have the same length" << std::endl;
1156 o <<
"[" <<
mRows[count].columnIndices[i] <<
"," << b.
str() <<
"] ";
1171 Monom m(monomInserter.data());
1173 o << b.
str() <<
"(" << i.second.first <<
", " << i.second.second <<
") ";
1180 o <<
"***ERROR*** expected mRows and mReducersTodo to have the same length!" << std::endl;
1184 for (
auto count = 0; count <
mRows.size(); ++count)
1187 o << count <<
" ("<< pr.
left <<
", "
1194 mRows[count].columnIndices[count2] != i)
1202 o <<
" " << b.
str() <<
" ";
1212 for (
auto r : rowsVector)
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::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)
NCF4(const FreeAlgebra &A, const ConstPolyList &input, int hardDegreeLimit, int strategy, int numThreads)
auto overlapHeft(Overlap o) const -> int
void reduceF4Row(int index, int first, int firstcol, NCF4Stats &ncF4Stats, ElementArray &dense)
void displayF4Matrix(std::ostream &o) const
MemoryBlock mPreviousMonomialSpace
auto isOverlapNecessary(const Overlap &o) -> bool
ColumnsVector mPreviousColumns
void parallelReduceF4Matrix()
void parallelReduceF4Row(int index, int first, int firstcol, NCF4Stats &ncF4Stats, ElementArray &dense, mtbb::queuing_mutex &lock)
const ConstPolyList mInput
mtbb::feeder< PreRow > PreRowFeeder
void parallelBuildF4Matrix(const std::deque< Overlap > &overlapsToProcess)
void generalReduceF4Row(int index, int first, int firstcol, NCF4Stats &ncF4Stats, ElementArray &dense, bool updateColumnIndex, LockType &lock)
void addToGroebnerBasis(Poly *toAdd)
ring_elem getCoeffOfMonom(const Poly &f, const Monom &m) const
void clearRows(RowsVector &rowsVector)
mtbb::queuing_mutex mColumnMutex
std::vector< MemoryBlock * > mMemoryBlocks
void updateOverlaps(const Poly *toAdd)
void processPreviousF4Matrix()
std::vector< PreRow > mOverlapsTodo
MonomHashEqual mMonomHashEqual
PolyList newGBelements() const
void reducedRowToPoly(Poly *result, const RowsVector &rows, const ColumnsVector &cols, int i) const
void processPreRow(PreRow r, RowsVector &rowsVector, MemoryBlock &memoryBlock, PreRowFeeder *feeder)
std::vector< Row, gc_allocator< Row > > RowsVector
MonomialHash mColumnMonomials
void preRowsFromOverlap(const Overlap &o)
const FreeAlgebra & mFreeAlgebra
std::pair< bool, int > findPreviousReducerSuffix(const Word &w)
std::vector< MemoryBlock * > mPreviousMemoryBlocks
void processWordInPreRow(Word &w, PreRowFeeder *feeder)
void displayFullF4Matrix(std::ostream &o) const
std::pair< bool, PreRow > findDivisor(Word w)
Word createOverlapLeadWord(const Overlap &o)
void displayF4MatrixSize(std::ostream &o) const
auto checkOldOverlaps(Word &newLeadWord) -> void
MemoryBlock mMonomialSpace
std::vector< PreRow > mReducersTodo
void labelAndSortF4Matrix()
const VectorArithmetic * mVectorArithmetic
std::vector< Column > ColumnsVector
void compute(int softDegreeLimit)
std::pair< bool, int > findPreviousReducerPrefix(const Word &w)
auto insertNewOverlaps(std::vector< Overlap > &newOverlaps) -> void
mtbb::task_arena mScheduler
void buildF4Matrix(const std::deque< Overlap > &overlapsToProcess)
OverlapTable mOverlapTable
const FreeAlgebra & freeAlgebra() const
void autoreduceByLastElement()
MonomialHash mPreviousColumnMonomials
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
Runtime dispatcher that hides the concrete coefficient ring behind a std::variant of ConcreteVectorAr...
const int * begin() const
void init(const int *begin, const int *end)
Non-owning view of a non-commutative word: [begin, end) of int variable indices.
static void subwordPositions(Word word1, Word word2, std::vector< int > &result_start_indices)
VALGRIND_MAKE_MEM_DEFINED & result(result)
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)
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...
Per-thread counters tracking how much work the F4 reduction did.
Symbolic description of one row before it is materialised in the matrix: a left * (something) * right...
A materialised row of the Macaulay matrix: parallel coefficient and monomial arrays.
void emit_wrapped(const char *s)
Text-formatting helpers layered on buffer: bignum print, line wrapping, M2_gbTrace-gated emit.
double seconds(DurationType time_diff)