bool ReducerPackDedup<Q>::leadTerm(NewConstTerm& result) { if (!mLeadTermKnown) { do { if (mQueue.empty()) return false; auto entry = mQueue.top(); entry->currentCoefficient(mRing, mLeadTerm.coef); while (true) { // store the chained elements const auto chainBegin = entry->chain; const auto chainEnd = entry; // the list is circular entry->chain = entry; // detach any chained elements // handle the entry itself std::swap(mLeadTerm.mono, entry->current); ++entry->pos; if (entry->pos == entry->end) { mQueue.pop(); entry->destroy(mRing); mPool.free(entry); } else { entry->computeCurrent(mRing); // Inserted spans must be in descending order MATHICGB_ASSERT(mQueue.getConfiguration().ring(). monoid().lessThan(*entry->current, *mLeadTerm.mono)); mQueue.decreaseTop(entry); } // handle any chained elements auto chain = chainBegin; while (chain != chainEnd) { MATHICGB_ASSERT(chain != 0); MATHICGB_ASSERT(mRing.monoid().equal(*chain->current, *mLeadTerm.mono)); const auto next = chain->chain; chain->chain = chain; // detach from remaining chained elements chain->addCurrentCoefficient(mRing, mLeadTerm.coef); ++chain->pos; if (chain->pos == chain->end) { chain->destroy(mRing); mPool.free(chain); } else { chain->computeCurrent(mRing); // Inserted spans must be in descending order MATHICGB_ASSERT(mQueue.getConfiguration().ring(). monoid().lessThan(*chain->current, *mLeadTerm.mono)); mQueue.push(chain); } chain = next; } if (mQueue.empty()) break; entry = mQueue.top(); if (!mRing.monoid().equal(*entry->current, *mLeadTerm.mono)) break; entry->addCurrentCoefficient(mRing, mLeadTerm.coef); } } while (mRing.coefficientIsZero(mLeadTerm.coef)); mLeadTermKnown = true; } result = mLeadTerm; return true; }
void stop() {MATHICGB_ASSERT(false);}
size_t SigPolyBasis::minimalLeadInSig(ConstMonoRef sig) const { const auto component = monoid().component(sig); const auto minLeadGen = mSignatureLookup[component]->minimalLeadInSig(sig); MATHICGB_ASSERT(minLeadGen == minimalLeadInSigSlow(sig)); return minLeadGen; }
void SigPolyBasis::insert(Mono ownedSig, std::unique_ptr<Poly> f) { MATHICGB_ASSERT(f.get() != nullptr); MATHICGB_ASSERT(!f->isZero()); MATHICGB_ASSERT(!field().isZero(f->leadCoef())); MATHICGB_ASSERT(!ownedSig.isNull()); MATHICGB_ASSERT(monoid().fromPool(*ownedSig)); const auto index = mSignatures.size(); mSignatures.push_back(ownedSig.release()); auto sig = *mSignatures.back(); const auto component = monoid().component(sig); MATHICGB_ASSERT(component < mSignatureLookup.size()); mSignatureLookup[component]->insert(sig, index); auto ratio = ring().allocMonomial(); monoid().divideToNegative(f->leadMono(), sig, ratio); mSigLeadRatio.push_back(ratio); const auto lead = f->leadMono(); mBasis.insert(std::move(f)); if (mBasis.leadMinimal(mBasis.size() - 1)) { mMinimalMonoLookup->removeMultiples(lead); mMinimalMonoLookup->insert(lead, index); } MATHICGB_ASSERT(mMinimalMonoLookup->type() == 0 || mBasis.minimalLeadCount() == mMinimalMonoLookup->size()); MATHICGB_ASSERT(mSignatures.size() == index + 1); MATHICGB_ASSERT(mBasis.size() == index + 1); if (!mUseRatioRank) return; // compute rank of the ratio auto pos = mRatioSorted.insert(index); again: Rank prevRank; if (pos == mRatioSorted.begin()) prevRank = 0; else { auto prev = pos; --prev; prevRank = mRatioRanks[*prev]; if (monoid().equal(ratio, *mSigLeadRatio[*prev])) { mRatioRanks.push_back(prevRank); return; } } Rank nextRank; auto next = pos; ++next; if (next == mRatioSorted.end()) nextRank = std::numeric_limits<Rank>::max(); else { nextRank = mRatioRanks[*next]; if (monoid().equal(ratio, *mSigLeadRatio[*next])) { mRatioRanks.push_back(nextRank); return; } } MATHICGB_ASSERT(prevRank < nextRank); // this formula avoids the overflow inherent in prevRank + nextRank; Rank rank = prevRank + (nextRank - prevRank) / 2; // must have at least 1 space between ranks to support // queries for non-basis element rank if (rank == 0 || // must leave space for smaller ratio rank == std::numeric_limits<Rank>::max() || // shouldn't happen nextRank - prevRank < 4) { // 4 as require: prev, gap, new, gap, next // size plus 1 to account for the gaps at the beginning and end. size_t increment = std::numeric_limits<Rank>::max() / (mSignatures.size() + 1); if (increment == 0) increment = 2; MATHICGB_ASSERT(!mRatioSorted.empty()); size_t rankSum = increment; // leave a gap at beginning Rank prevRank = *mRatioRanks.begin(); auto end = mRatioSorted.end(); for (auto it = mRatioSorted.begin(); it != end; ++it) { if (it == pos) continue; if (mRatioRanks[*it] != prevRank) rankSum += increment; prevRank = mRatioRanks[*it]; mRatioRanks[*it] = rankSum; } goto again; } MATHICGB_ASSERT(rank > 0); MATHICGB_ASSERT(rank < std::numeric_limits<Rank>::max()); MATHICGB_ASSERT(prevRank + 1 < rank && rank < nextRank - 1); mRatioRanks.push_back(rank); MATHICGB_ASSERT(mRatioRanks.size() == index + 1); #ifdef MATHICGB_DEBUG // Check that at least one space has been left between every rank MATHICGB_ASSERT(mRatioRanks[*mRatioSorted.begin()] > 0); MATHICGB_ASSERT(mRatioRanks[*mRatioSorted.rbegin()] < std::numeric_limits<Rank>::max()); auto it2 = mRatioSorted.begin(); for (++it2; it2 != mRatioSorted.end(); ++it2) { auto prev = it2; --prev; MATHICGB_ASSERT(mRatioRanks[*it2] == mRatioRanks[*prev] || mRatioRanks[*it2] - 1 > mRatioRanks[*prev]); } #endif }
void CommonParams::registerFileNameExtension(std::string extension) { MATHICGB_ASSERT(!extension.empty()); mExtensions.push_back(std::move(extension)); }
std::string CommonParams::inputFileName(size_t i) { MATHICGB_ASSERT(i < inputFileCount()); return mDirectParameters[i]; }
SigSPairs::~SigSPairs() { MATHICGB_ASSERT(mUseBaseDivisors || mUseHighBaseDivisors || mKnownSyzygyTri.empty()); }
void SigSPairs::setupBaseDivisors( BaseDivisor& divisor1, BaseDivisor& divisor2, size_t& highDivisorCmp, size_t newGenerator ) { BaseDivContainer divisors; const size_t MaxBaseDivisors = 2; if (mUseBaseDivisors || mUseHighBaseDivisors) divisors.reserve(MaxBaseDivisors + 1); MATHICGB_ASSERT(mUseBaseDivisors || mUseHighBaseDivisors); MATHICGB_ASSERT(mKnownSyzygyTri.columnCount() == newGenerator); mKnownSyzygyTri.addColumn(); if (mUseHighBaseDivisors) { size_t highDivisor = GB->highBaseDivisor(newGenerator); if (highDivisor != static_cast<size_t>(-1)) { // To use a high divisor, the ratio of the other generator has to be // greater than both the ratio of newGenerator and of the high ratio // divisor. We can check both at once by letting highDivisorCmp // be the one out of newGenerator and highDivisor that has the // highest ratio. if (GB->ratioCompare(newGenerator, highDivisor) == GT) highDivisorCmp = newGenerator; else highDivisorCmp = highDivisor; } } else highDivisorCmp = static_cast<size_t>(-1); if (!mUseBaseDivisors) return; std::vector<size_t> divs; GB->lowBaseDivisors(divs, MaxBaseDivisors, newGenerator); MATHICGB_ASSERT(divs.size() <= MaxBaseDivisors); divisors.resize(divs.size()); for (size_t i = 0; i < divisors.size(); ++i) { BaseDivisor& bd = divisors[i]; bd.baseDivisor = divs[i]; // Only use the base divisor technique for generators with ratio // less than both N and baseDivisor. baseDivisorCmp is the // smallest one of these, so it can be used for this comparison. if (GB->ratioCompare(newGenerator, bd.baseDivisor) == LT) bd.ratioLessThan = newGenerator; else bd.ratioLessThan = bd.baseDivisor; // Construct a monomial in makeSPair_t2 that can be used // to eliminate s-pairs quickly based on the s-pairs already // eliminated for baseDivisor. auto newSig = GB->signature(newGenerator); auto newLead = GB->leadMono(newGenerator); auto baseDivSig = GB->signature(bd.baseDivisor); auto baseDivLead = GB->leadMono(bd.baseDivisor); bd.baseMonomial = R->allocMonomial(); R->mysteriousSPairMonomialRoutine( Monoid::toOld(newSig), Monoid::toOld(newLead), Monoid::toOld(baseDivSig), Monoid::toOld(baseDivLead), bd.baseMonomial ); } divisor1.baseDivisor = static_cast<size_t>(-1); divisor2.baseDivisor = static_cast<size_t>(-1); if (divisors.size() >= 1) divisor1 = divisors.front(); if (divisors.size() == 2) { divisor2 = divisors.back(); MATHICGB_ASSERT(GB->ratioCompare (divisor1.ratioLessThan, divisor2.ratioLessThan) != LT); } }
void SigSPairs::makePreSPairs(size_t newGen) { MATHICGB_ASSERT(mIndexSigs.empty()); MATHICGB_ASSERT(newGen < GB->size()); mStats.spairsConstructed += newGen; monomial baseDivisorMonomial = 0; BaseDivisor divisor1; BaseDivisor divisor2; divisor1.baseDivisor = static_cast<size_t>(-1); divisor2.baseDivisor = static_cast<size_t>(-1); size_t highDivisorCmp = static_cast<size_t>(-1); if (mUseBaseDivisors || mUseHighBaseDivisors) setupBaseDivisors(divisor1, divisor2, highDivisorCmp, newGen); monomial hsyz = 0; if (!mPostponeKoszuls) hsyz = R->allocMonomial(); auto newSig = GB->signature(newGen); auto newLead = GB->leadMono(newGen); auto pairSig = R->allocMonomial(); if (mUseHighBaseDivisors && divisor1.baseDivisor != static_cast<size_t>(-1)) ++mStats.hasLowBaseDivisor; if (mUseHighBaseDivisors && highDivisorCmp != static_cast<size_t>(-1)) ++mStats.hasHighBaseDivisor; PreSPair result; for (size_t oldGen = 0; oldGen < newGen; oldGen++) { auto oldSig = GB->signature(oldGen); auto oldLead = GB->leadMono(oldGen); // Check whether this is a non-regular spair. // 'cmp' is used below too. const int cmp = GB->ratioCompare(newGen, oldGen); if (cmp == EQ) { ++mStats.nonregularSPairs; continue; } // check high ratio divisor if (mUseHighBaseDivisors && highDivisorCmp != static_cast<size_t>(-1) && GB->ratioCompare(oldGen, highDivisorCmp) == GT && mKnownSyzygyTri.bitUnordered(oldGen, highDivisorCmp)) { MATHICGB_ASSERT(oldGen != highDivisorCmp); // otherwise ratios should be equal mKnownSyzygyTri.setBit(newGen, oldGen, true); ++mStats.highBaseDivisorHits; // if DEBUG defined, get to the ASSERT below stating // that this is really a syzygy #ifndef DEBUG continue; #endif } // check low ratio divisors if (mUseBaseDivisors && divisor1.baseDivisor != static_cast<size_t>(-1) && GB->ratioCompare(oldGen, divisor1.ratioLessThan) == LT) { // if no divisor1, also no divisor 2 and also // divisor1 has larger ratio, so skip both checks if divisor1 fails due // to the ratio being too small or because there is no divisor1. if ( (divisor1.baseDivisor != oldGen && // if divisor1 is a hit mKnownSyzygyTri.bitUnordered(divisor1.baseDivisor, oldGen) && monoid().divides(oldLead, divisor1.baseMonomial)) || // or if divisor2 is a hit (divisor2.baseDivisor != static_cast<size_t>(-1) && GB->ratioCompare(oldGen, divisor2.ratioLessThan) == LT && divisor2.baseDivisor != oldGen && mKnownSyzygyTri.bitUnordered(divisor2.baseDivisor, oldGen) && monoid().divides(oldLead, divisor2.baseMonomial)) ) { mKnownSyzygyTri.setBit(newGen, oldGen, true); ++mStats.lowBaseDivisorHits; // if DEBUG defined, get to the ASSERT below stating // that this really is a syzygy. #ifndef DEBUG continue; #endif } } if (cmp == GT) monoid().colonMultiply(newLead, oldLead, newSig, pairSig); else { MATHICGB_ASSERT(cmp == LT); monoid().colonMultiply(oldLead, newLead, oldSig, pairSig); } if (Hsyz->member(pairSig)) { ++mStats.syzygyModuleHits; #ifdef DEBUG // Check if actually already elim. by low/high base divisor. // Only check in DEBUG mode as otherwise we would have taken an early // exit before getting here. if ((mUseBaseDivisors || mUseHighBaseDivisors) && mKnownSyzygyTri.bit(newGen, oldGen)) --mStats.syzygyModuleHits; #endif if (mUseBaseDivisors || mUseHighBaseDivisors) mKnownSyzygyTri.setBit(newGen, oldGen, true); continue; } MATHICGB_ASSERT((!mUseBaseDivisors && !mUseHighBaseDivisors) || !mKnownSyzygyTri.bit(newGen, oldGen)); if (!mPostponeKoszuls) { // add koszul syzygy to Hsyz. MATHICGB_ASSERT(cmp == GT || cmp == LT); if (cmp == GT) monoid().multiply(newSig, oldLead, hsyz); else monoid().multiply(oldSig, newLead, hsyz); if (Hsyz->insert(hsyz)) hsyz = R->allocMonomial(); if (monoid().relativelyPrime(newLead, oldLead)) { ++mStats.earlyRelativelyPrimePairs; continue; } } if (mUseSingularCriterionEarly) { MATHICGB_ASSERT(cmp == GT || cmp == LT); size_t const givesSig = (cmp == GT ? newGen : oldGen); if ( GB->ratioCompare(GB->minimalLeadInSig(pairSig), givesSig) == GT && !monoid().relativelyPrime(newLead, oldLead) ) { ++mStats.earlySingularCriterionPairs; continue; } } // construct the PreSPair result.signature = pairSig; pairSig = R->allocMonomial(); result.i = static_cast<BigIndex>(oldGen); mIndexSigs.push_back(result); ++mStats.queuedPairs; } R->freeMonomial(pairSig); if (mUseBaseDivisors && ! baseDivisorMonomial.isNull()) R->freeMonomial(baseDivisorMonomial); if (!mPostponeKoszuls) R->freeMonomial(hsyz); }
bool SignatureGB::step() { monomial sig = SP->popSignature(mSpairTmp); if (sig.isNull()) return false; ++stats_sPairSignaturesDone; stats_sPairsDone += mSpairTmp.size(); MATHICGB_IF_STREAM_LOG(SigSPairFinal) { stream << "Final processing of signature "; R->monomialDisplay(stream, sig); stream << '\n'; }; if (Hsyz->member(sig)) { ++stats_SignatureCriterionLate; SP->setKnownSyzygies(mSpairTmp); R->freeMonomial(sig); MATHICGB_LOG(SigSPairFinal) << " eliminated by signature criterion.\n"; return true; } while (!mKoszuls.empty() && R->monoid().lessThan(mKoszuls.top(), sig)) mKoszuls.pop(); if (!mKoszuls.empty() && R->monoid().equal(mKoszuls.top(), sig)) { ++stats_koszulEliminated; // This signature is of a syzygy that is not in Hsyz, so add it Hsyz->insert(sig); SP->newSyzygy(sig); SP->setKnownSyzygies(mSpairTmp); MATHICGB_LOG(SigSPairFinal) << " eliminated by Koszul criterion.\n"; return true; } if (mPostponeKoszul) { // Relatively prime check for (auto it = mSpairTmp.begin(); it != mSpairTmp.end(); ++it) { const_monomial a = GB->getLeadMonomial(it->first); const_monomial b = GB->getLeadMonomial(it->second); if (R->monomialRelativelyPrime(a, b)) { ++stats_relativelyPrimeEliminated; Hsyz->insert(sig); SP->newSyzygy(sig); SP->setKnownSyzygies(mSpairTmp); MATHICGB_LOG(SigSPairFinal) << " eliminated by relatively prime criterion.\n"; return true; } } } #ifdef DEBUG for (auto it = mSpairTmp.begin(); it != mSpairTmp.end(); ++it) { const_monomial a = GB->getLeadMonomial(it->first); const_monomial b = GB->getLeadMonomial(it->second); MATHICGB_ASSERT(!R->monomialRelativelyPrime(a, b)); } #endif // Reduce the pair ++stats_pairsReduced; if (!processSPair(sig, mSpairTmp) || !mPostponeKoszul) return true; for (auto it = mSpairTmp.begin(); it != mSpairTmp.end(); ++it) { std::pair<size_t, size_t> p = *it; if (GB->ratioCompare(p.first, p.second) == LT) std::swap(p.first, p.second); const_monomial greaterSig = GB->getSignature(p.first); const_monomial smallerLead = GB->getLeadMonomial(p.second); monomial koszul = R->allocMonomial(); R->monomialMult(greaterSig, smallerLead, koszul); if (Hsyz->member(koszul)) R->freeMonomial(koszul); else mKoszuls.push(koszul); } return true; }
virtual void insert(monomial multiplier, const Poly* f) { MATHICGB_ASSERT(f != 0); ConstMonoRef mono = multiplier; insert(mono, *f); }
// These are the methods that sub-classes define in order to carry // out sub-steps in the reduction. virtual void insertTail(const_term multiplier, const Poly* f) { MATHICGB_ASSERT(f != 0); NewConstTerm t = {multiplier.monom, multiplier.coeff}; insertTail(t, *f); }
const Poly *getPoly(size_t i) const { MATHICGB_ASSERT(i < size()); return mGenerators[i].get(); }