Example #1
0
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;
}
Example #2
0
 void stop() {MATHICGB_ASSERT(false);}
Example #3
0
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;
}
Example #4
0
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
}
Example #5
0
void CommonParams::registerFileNameExtension(std::string extension) {
  MATHICGB_ASSERT(!extension.empty());
  mExtensions.push_back(std::move(extension));
}
Example #6
0
std::string CommonParams::inputFileName(size_t i) {
  MATHICGB_ASSERT(i < inputFileCount());
  return mDirectParameters[i];
}
Example #7
0
SigSPairs::~SigSPairs()
{
  MATHICGB_ASSERT(mUseBaseDivisors || mUseHighBaseDivisors || mKnownSyzygyTri.empty());
}
Example #8
0
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);
  }
}
Example #9
0
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);
}
Example #10
0
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;
}
Example #11
0
 virtual void insert(monomial multiplier, const Poly* f) {
   MATHICGB_ASSERT(f != 0);
   ConstMonoRef mono = multiplier;
   insert(mono, *f);
 }
Example #12
0
 // 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);
 }
Example #13
0
 const Poly *getPoly(size_t i) const {
   MATHICGB_ASSERT(i < size());
   return mGenerators[i].get();
 }