[mathicgb] 39/393: Added an option -sPairGroupSize that makes MathicGB reduce that many S-pairs at the same time. As you would expect, this is a big benefit for the F4Reducer (reducer 25).

Doug Torrance dtorrance-guest at moszumanska.debian.org
Fri Apr 3 15:58:29 UTC 2015


This is an automated email from the git hooks/post-receive script.

dtorrance-guest pushed a commit to branch upstream
in repository mathicgb.

commit 7ae17cc4035030ba06c99c21ec575dafaac73c6c
Author: Bjarke Hammersholt Roune <bjarkehr.code at gmail.com>
Date:   Fri Sep 28 21:03:09 2012 +0200

    Added an option -sPairGroupSize that makes MathicGB reduce that many S-pairs at the same time. As you would expect, this is a big benefit for the F4Reducer (reducer 25).
---
 src/cli/GBMain.cpp                |  19 ++-
 src/mathicgb/BjarkeGeobucket2.cpp |   5 +-
 src/mathicgb/BuchbergerAlg.cpp    | 103 ++++++++++-----
 src/mathicgb/BuchbergerAlg.hpp    |   7 +-
 src/mathicgb/F4MatrixReducer.cpp  |   9 +-
 src/mathicgb/F4Reducer.cpp        |  35 ++++++
 src/mathicgb/F4Reducer.hpp        |   5 +
 src/mathicgb/PolyBasis.cpp        |   3 +
 src/mathicgb/PolyBasis.hpp        |  62 ++++-----
 src/mathicgb/PolyRing.hpp         |   3 +-
 src/mathicgb/Reducer.hpp          |   8 ++
 src/mathicgb/SPairs.cpp           |  28 ++---
 src/mathicgb/TypicalReducer.cpp   |  12 ++
 src/mathicgb/TypicalReducer.hpp   |   5 +
 src/test/gb-test.cpp              | 258 +++++++++++++++++++++-----------------
 src/test/pict.in                  |   1 +
 16 files changed, 361 insertions(+), 202 deletions(-)

diff --git a/src/cli/GBMain.cpp b/src/cli/GBMain.cpp
index a29b450..8790377 100755
--- a/src/cli/GBMain.cpp
+++ b/src/cli/GBMain.cpp
@@ -113,7 +113,14 @@ public:
       "  2   late koszul\n"
       "  4   not used (used to be MES reduction)\n"
       "  8   signature\n",
-      2)
+     2),
+
+    mSPairGroupSize("sPairGroupSize",
+      "Specifies how many S-pair to reduce at one time. A value of 0 "
+      "indicates not to group S-pairs together. Only currently relevant "
+      "for the classic Buchberger algorithm.",
+     0)
+
   {
     {
       std::ostringstream orderOut;
@@ -185,6 +192,7 @@ public:
         mSPairQueue.value());
       alg.setBreakAfter(mBreakAfter.value());
       alg.setPrintInterval(mPrintInterval.value());
+      alg.setSPairGroupSize(mSPairGroupSize.value());
       alg.setUseAutoTopReduction(mAutoTopReduce.value());
       alg.setUseAutoTailReduction(mAutoTailReduce.value());
 
@@ -270,10 +278,12 @@ public:
     parameters.push_back(&mReducer);
     parameters.push_back(&mModuleOrder);
     parameters.push_back(&mProjectName);
+    parameters.push_back(&mSPairGroupSize);
 
-    // do not expose the strategy parameter - it is only here to support
-    // the old format of using direct numeric parameters to the action.
-    //parameters.push_back(&mStrategy);
+    // we do not expose the strategy parameter - it is only here to
+    // support the old format of using direct numeric parameters to
+    // the action.
+    // parameters.push_back(&mStrategy);
   }
 
 private:
@@ -294,6 +304,7 @@ private:
   mic::IntegerParameter mModuleOrder;
   mic::StringParameter mProjectName;
   mic::IntegerParameter mStrategy;
+  mic::IntegerParameter mSPairGroupSize;
 };
 
 int oldmain(int argc, char **argv);
diff --git a/src/mathicgb/BjarkeGeobucket2.cpp b/src/mathicgb/BjarkeGeobucket2.cpp
index 008b71b..ef384a7 100755
--- a/src/mathicgb/BjarkeGeobucket2.cpp
+++ b/src/mathicgb/BjarkeGeobucket2.cpp
@@ -1,9 +1,10 @@
 // Copyright 2011 Michael E. Stillman
-
-#include <iostream>
 #include "stdinc.h"
 #include "BjarkeGeobucket2.hpp"
 
+#include <iostream>
+
+
 extern int tracingLevel;
 
 BjarkeGeobucket2::BjarkeGeobucket2(const PolyRing *R0):
diff --git a/src/mathicgb/BuchbergerAlg.cpp b/src/mathicgb/BuchbergerAlg.cpp
index ba70aeb..d9efa37 100755
--- a/src/mathicgb/BuchbergerAlg.cpp
+++ b/src/mathicgb/BuchbergerAlg.cpp
@@ -16,6 +16,7 @@ BuchbergerAlg::BuchbergerAlg(
 ):
   mBreakAfter(0),
   mPrintInterval(0),
+  mSPairGroupSize(0),
   mUseAutoTopReduction(true),
   mUseAutoTailReduction(false),
   mRing(*ideal.getPolyRing()),
@@ -140,31 +141,70 @@ void BuchbergerAlg::computeGrobnerBasis() {
   }
   //printStats(std::cerr);
   //mReducer->dump();
+
+  for (size_t i = 0; i < mBasis.size(); ++i)
+    if (!mBasis.retired(i))
+      mBasis.replaceSameLeadTerm
+        (i, mReducer->classicTailReduce(mBasis.poly(i), mBasis));
 }
 
 void BuchbergerAlg::step() {
   ASSERT(!mSPairs.empty());
   if (tracingLevel > 30)
     std::cerr << "Determining next S-pair" << std::endl;
-  std::pair<size_t, size_t> p = mSPairs.pop();
-  if (p.first == static_cast<size_t>(-1)) {
-    ASSERT(p.second == static_cast<size_t>(-1));
-    return; // no more S-pairs
-  }
-  ASSERT(p.first != static_cast<size_t>(-1));
-  ASSERT(p.second != static_cast<size_t>(-1));
-  ASSERT(!mBasis.retired(p.first));
-  ASSERT(!mBasis.retired(p.second));
 
-  if (tracingLevel > 20) {
-    std::cerr << "Reducing S-pair ("
-      << p.first << ", "
-      << p.second << ")" << std::endl;
-  }
-  std::unique_ptr<Poly> reduced(mReducer->classicReduceSPoly
-    (mBasis.poly(p.first), mBasis.poly(p.second), mBasis));
-  if (!reduced->isZero()) {
-    insertReducedPoly(std::move(reduced));
+  if (mSPairGroupSize == 0) {
+    std::pair<size_t, size_t> p = mSPairs.pop();
+    if (p.first == static_cast<size_t>(-1)) {
+      ASSERT(p.second == static_cast<size_t>(-1));
+      return; // no more S-pairs
+    }
+    ASSERT(p.first != static_cast<size_t>(-1));
+    ASSERT(p.second != static_cast<size_t>(-1));
+    ASSERT(!mBasis.retired(p.first));
+    ASSERT(!mBasis.retired(p.second));
+
+    if (tracingLevel > 20) {
+      std::cerr << "Reducing S-pair ("
+                << p.first << ", "
+                << p.second << ")" << std::endl;
+    }
+    std::unique_ptr<Poly> reduced
+      (mReducer->classicReduceSPoly
+       (mBasis.poly(p.first), mBasis.poly(p.second), mBasis));
+    if (!reduced->isZero()) {
+      insertReducedPoly(std::move(reduced));
+      if (mUseAutoTailReduction)
+        autoTailReduce();
+    }
+  } else {
+    std::vector<std::pair<size_t, size_t> > spairGroup;
+    for (unsigned int i = 0; i < mSPairGroupSize; ++i) {
+      std::pair<size_t, size_t> p = mSPairs.pop();
+      if (p.first == static_cast<size_t>(-1)) {
+        ASSERT(p.second == static_cast<size_t>(-1));
+        break; // no more S-pairs
+      }
+      ASSERT(p.first != static_cast<size_t>(-1));
+      ASSERT(p.second != static_cast<size_t>(-1));
+      ASSERT(!mBasis.retired(p.first));
+      ASSERT(!mBasis.retired(p.second));
+
+      spairGroup.push_back(p);
+    }
+    if (spairGroup.empty())
+      return; // no more s-pairs
+    std::vector<std::unique_ptr<Poly> > reduced;
+    mReducer->classicReduceSPolyGroup(spairGroup, mBasis, reduced);
+    
+    for (auto it = reduced.begin(); it != reduced.end(); ++it) {
+      auto p = std::move(*it);
+      MATHICGB_ASSERT(!p->isZero());
+      if (it != reduced.begin())
+        p = mReducer->classicReduce(*p, mBasis);
+      if (!p->isZero())
+        insertReducedPoly(std::move(p));
+    }
     if (mUseAutoTailReduction)
       autoTailReduce();
   }
@@ -197,6 +237,7 @@ void BuchbergerAlg::printStats(std::ostream& out) const {
   out << " divisor tab type:   " << mBasis.divisorLookup().getName() << '\n';
   out << " S-pair queue type:  " << mSPairs.name() << '\n';
   out << " total compute time: " << mTimer.getMilliseconds()/1000.0 << " seconds " << '\n';
+  out << " S-pair group size:  " << mSPairGroupSize << '\n';
 
   const PolyRing::coefficientStats& cstats = mRing.getCoefficientStats();
   out << "n-coeff-add:         " << cstats.n_add << '\n';
@@ -221,32 +262,32 @@ void BuchbergerAlg::printStats(std::ostream& out) const {
   name << "Time spent:\n";
   value << mTimer << '\n';
   extra << mic::ColumnPrinter::oneDecimal(mseconds / basisSize)
-    << " ms per basis element\n";
+        << " ms per basis element\n";
 
   const double pendingRatio = static_cast<double>(pending) / basisSize;
   name << "Basis elements:\n";
   value << mic::ColumnPrinter::commafy(basisSize) << '\n';
   extra << mic::ColumnPrinter::oneDecimal(pendingRatio)
-    << " Sp pend per basis ele\n";
+        << " Sp pend per basis ele\n";
 
   const size_t basisTermCount = mBasis.monomialCount();
   name << "Terms for basis:\n";
   value << mic::ColumnPrinter::commafy(basisTermCount) << '\n';
   extra << mic::ColumnPrinter::ratio(basisTermCount, basisSize)
-    << " terms per basis ele\n";
+        << " terms per basis ele\n";
 
   const size_t minLeadCount = mBasis.minimalLeadCount();
   name << "Minimum lead terms:\n";
   value << mic::ColumnPrinter::commafy(minLeadCount) << '\n';
   extra << mic::ColumnPrinter::percent(minLeadCount, basisSize)
-    << " basis ele have min lead\n";
+        << " basis ele have min lead\n";
 
   const size_t lastMinLead = mBasis.maxIndexMinimalLead() + 1;
   const size_t timeSinceLastMinLead = basisSize - lastMinLead;
   name << "Index of last min lead:\n";
   value << mic::ColumnPrinter::commafy(lastMinLead) << '\n';
   extra << mic::ColumnPrinter::percent(timeSinceLastMinLead, basisSize)
-    << " of basis added since then\n";
+        << " of basis added since then\n";
 
   const unsigned long long considered =
     mBasis.size() * (mBasis.size() - 1) / 2;
@@ -257,7 +298,7 @@ void BuchbergerAlg::printStats(std::ostream& out) const {
   name << "S-pairs pending:\n";
   value << mic::ColumnPrinter::commafy(pending) << '\n';
   extra << mic::ColumnPrinter::percent(pending, considered)
-    << " of considered\n";
+        << " of considered\n";
 
   unsigned long long const reductions = sPolyReductionCount();
   name << "S-pairs reduced:\n";
@@ -271,27 +312,27 @@ void BuchbergerAlg::printStats(std::ostream& out) const {
   name << "Rel.prime sp eliminated:\n";
   value << mic::ColumnPrinter::commafy(primeElim) << '\n';
   extra << mic::ColumnPrinter::percent(primeElim, reductions)
-    << " of late eliminations\n";
+        << " of late eliminations\n";
 
   const unsigned long long singularReductions =
     reducerStats.singularReductions;
   name << "Singular reductions:\n";
   value << mic::ColumnPrinter::commafy(singularReductions) << '\n';
   extra << mic::ColumnPrinter::percent(singularReductions, reductions)
-    << " of reductions\n";
+        << " of reductions\n";
 
   const unsigned long long zeroReductions = reducerStats.zeroReductions;
   name << "Reductions to zero:\n";
   value << mic::ColumnPrinter::commafy(zeroReductions) << '\n';
   extra << mic::ColumnPrinter::percent(zeroReductions, reductions)
-    << " of reductions\n";
+        << " of reductions\n";
 
   const unsigned long long newReductions =
     reductions - singularReductions - zeroReductions;
   name << "Reductions to new ele:\n";
   value << mic::ColumnPrinter::commafy(newReductions) << '\n';
   extra << mic::ColumnPrinter::percent(newReductions, reductions)
-    << " of reductions\n";
+        << " of reductions\n";
 
   const unsigned long long redSteps = reducerStats.steps;
   const double stepsRatio =
@@ -299,7 +340,7 @@ void BuchbergerAlg::printStats(std::ostream& out) const {
   name << "Sig reduction steps:\n";
   value << mic::ColumnPrinter::commafy(redSteps) << '\n';
   extra << mic::ColumnPrinter::oneDecimal(stepsRatio)
-    << " steps per non-sing reduction\n";
+        << " steps per non-sing reduction\n";
 
   const unsigned long long longestReduction = reducerStats.maxSteps;
   name << "Longest sig reduction:\n";
@@ -317,7 +358,7 @@ void BuchbergerAlg::printStats(std::ostream& out) const {
   name << "Classic reduction steps:\n";
   value << mic::ColumnPrinter::commafy(clRedSteps) << '\n';
   extra << mic::ColumnPrinter::oneDecimal(clStepsRatio)
-    << " steps per reduction\n";
+        << " steps per reduction\n";
 
   const unsigned long long clLongestReduction = classicRedStats.maxSteps;
   name << "Longest classic red:\n";
@@ -368,7 +409,7 @@ void BuchbergerAlg::printStats(std::ostream& out) const {
     " of simple hits\n";
 
   out << "***** Classic Buchberger algorithm statistics *****\n"
-    << pr << std::flush;
+      << pr << std::flush;
 }
 
 void BuchbergerAlg::printMemoryUse(std::ostream& out) const
diff --git a/src/mathicgb/BuchbergerAlg.hpp b/src/mathicgb/BuchbergerAlg.hpp
old mode 100644
new mode 100755
index 4a03a1f..4b15b19
--- a/src/mathicgb/BuchbergerAlg.hpp
+++ b/src/mathicgb/BuchbergerAlg.hpp
@@ -9,7 +9,7 @@
 #include <memory>
 #include <ostream>
 
-// Calculates a non-signature Grobner basis using Buchberger's algorithm.
+/// Calculates a classic Grobner basis using Buchberger's algorithm.
 class BuchbergerAlg {
 public:
   BuchbergerAlg(
@@ -45,6 +45,10 @@ public:
     mPrintInterval = reductions;
   }
 
+  void setSPairGroupSize(unsigned int groupSize) {
+    mSPairGroupSize = groupSize;
+  }
+
   void setUseAutoTopReduction(bool value) {
     mUseAutoTopReduction = value;
   }
@@ -56,6 +60,7 @@ public:
 private:
   unsigned int mBreakAfter;
   unsigned int mPrintInterval;
+  unsigned int mSPairGroupSize;
   bool mUseAutoTopReduction;
   bool mUseAutoTailReduction;
 
diff --git a/src/mathicgb/F4MatrixReducer.cpp b/src/mathicgb/F4MatrixReducer.cpp
index b29c00b..b9131e1 100755
--- a/src/mathicgb/F4MatrixReducer.cpp
+++ b/src/mathicgb/F4MatrixReducer.cpp
@@ -343,8 +343,8 @@ void myReduceToEchelonForm5
     dense[row].addRow(toReduce, row);
   }
 
-  // invariant: all columns to the left of leadCols[row] are zero.
-  std::vector<size_t> leadCols(colCount);
+  // invariant: all columns in row to the left of leadCols[row] are zero.
+  std::vector<size_t> leadCols(rowCount);
 
   // pivot rows get copied here before being used to reduce the matrix.
   SparseMatrix reduced;
@@ -367,8 +367,9 @@ void myReduceToEchelonForm5
     size_t const reducerCount = reduced.rowCount();
 
     //std::cout << "reducing " << reduced.rowCount() << " out of " << toReduce.rowCount() << std::endl;
-#pragma omp parallel for num_threads(threadCount) schedule(dynamic)
+    //#pragma omp parallel for num_threads(threadCount) schedule(dynamic)
     for (size_t row = 0; row < rowCount; ++row) {
+      MATHICGB_ASSERT(leadCols[row] <= colCount);
       DenseRow<uint64>& denseRow = dense[row];
       if (denseRow.empty())
         continue;
@@ -383,12 +384,14 @@ void myReduceToEchelonForm5
 
       // update leadCols[row]
       size_t col;
+      MATHICGB_ASSERT(leadCols[row] <= colCount);
       for (col = leadCols[row]; col < colCount; ++col) {
         denseRow[col] %= modulus;
         if (denseRow[col] != 0)
           break;
       }
       leadCols[row] = col;
+      MATHICGB_ASSERT(leadCols[row] <= colCount);
 
       // note if we have found a new pivot row
       if (col == colCount)
diff --git a/src/mathicgb/F4Reducer.cpp b/src/mathicgb/F4Reducer.cpp
index 5e865db..ce36501 100755
--- a/src/mathicgb/F4Reducer.cpp
+++ b/src/mathicgb/F4Reducer.cpp
@@ -52,6 +52,41 @@ std::unique_ptr<Poly> F4Reducer::classicReduceSPoly
   return p;
 }
 
+void F4Reducer::classicReduceSPolyGroup
+(std::vector<std::pair<size_t, size_t> >& spairs,
+ const PolyBasis& basis,
+ std::vector<std::unique_ptr<Poly> >& reducedOut)
+{
+  reducedOut.clear();
+  if (spairs.empty())
+    return;
+
+  SparseMatrix reduced;
+  std::vector<monomial> monomials;
+  {
+    QuadMatrix qm;
+    {
+      F4MatrixBuilder builder(basis);
+      for (auto it = spairs.begin(); it != spairs.end(); ++it) {
+        builder.addTwoRowsForSPairToMatrix
+          (basis.poly(it->first), basis.poly(it->second));
+      }
+      builder.buildMatrixAndClear(qm);
+
+      // there has to be something to reduce
+      MATHICGB_ASSERT(qm.bottomLeft.rowCount() > 0);
+    }
+    F4MatrixReducer().reduce(basis.ring(), qm, reduced);
+    monomials = std::move(qm.rightColumnMonomials);
+  }
+
+  for (SparseMatrix::RowIndex row = 0; row < reduced.rowCount(); ++row) {
+    auto p = make_unique<Poly>(&basis.ring());
+    reduced.rowToPolynomial(row, monomials, *p);
+    reducedOut.push_back(std::move(p));
+  }
+}
+
 Poly* F4Reducer::regularReduce
 (const_monomial sig,
  const_monomial multiple,
diff --git a/src/mathicgb/F4Reducer.hpp b/src/mathicgb/F4Reducer.hpp
index 4651011..c7f2e6c 100755
--- a/src/mathicgb/F4Reducer.hpp
+++ b/src/mathicgb/F4Reducer.hpp
@@ -17,6 +17,11 @@ public:
   virtual std::unique_ptr<Poly> classicReduceSPoly
   (const Poly& a, const Poly& b, const PolyBasis& basis);
 
+  virtual void classicReduceSPolyGroup
+  (std::vector<std::pair<size_t, size_t> >& spairs,
+   const PolyBasis& basis,
+   std::vector<std::unique_ptr<Poly> >& reducedOut);
+
   virtual Poly* regularReduce(
     const_monomial sig,
     const_monomial multiple,
diff --git a/src/mathicgb/PolyBasis.cpp b/src/mathicgb/PolyBasis.cpp
index e305773..aee8c5e 100755
--- a/src/mathicgb/PolyBasis.cpp
+++ b/src/mathicgb/PolyBasis.cpp
@@ -20,6 +20,8 @@ PolyBasis::PolyBasis(
 PolyBasis::~PolyBasis() {
   EntryIter const stop = mEntries.end();
   for (EntryIter it = mEntries.begin(); it != stop; ++it) {
+    if (it->retired)
+      continue;
     ASSERT(it->poly != 0);
     delete it->poly;
   }
@@ -80,6 +82,7 @@ void PolyBasis::insert(std::unique_ptr<Poly> poly) {
 
   if (mUseBuchbergerLcmHitCache)
     mBuchbergerLcmHitCache.push_back(0);
+  MATHICGB_ASSERT(mEntries.back().poly != 0);
 }
 
 size_t PolyBasis::divisor(const_monomial mon) const {
diff --git a/src/mathicgb/PolyBasis.hpp b/src/mathicgb/PolyBasis.hpp
index a350b35..ea86b24 100755
--- a/src/mathicgb/PolyBasis.hpp
+++ b/src/mathicgb/PolyBasis.hpp
@@ -41,15 +41,17 @@ public:
   // term of the new polynomial must be the same as the previous one.
   // This is useful for auto-tail-reduction.
   void replaceSameLeadTerm(size_t index, std::unique_ptr<Poly> newValue) {
-    ASSERT(index < size());
-    ASSERT(!retired(index));
-    ASSERT(newValue.get() != 0);
-    ASSERT(!newValue->isZero());
-    ASSERT(mRing.monomialEQ(leadMonomial(index), newValue->getLeadMonomial()));
+    MATHICGB_ASSERT(index < size());
+    MATHICGB_ASSERT(!retired(index));
+    MATHICGB_ASSERT(newValue.get() != 0);
+    MATHICGB_ASSERT(!newValue->isZero());
+    MATHICGB_ASSERT(mRing.monomialEQ
+                    (leadMonomial(index), newValue->getLeadMonomial()));
     mDivisorLookup->remove(leadMonomial(index));
     delete mEntries[index].poly;
     mEntries[index].poly = newValue.release();
     mDivisorLookup->insert(leadMonomial(index), index);    
+    MATHICGB_ASSERT(mEntries[index].poly != 0);
   }
 
   struct Stats {
@@ -110,8 +112,8 @@ public:
   // to it, including the basis element polynomial, and marks it as retired. 
   // todo: implement
   std::unique_ptr<Poly> retire(size_t index) {
-    ASSERT(index < size());
-    ASSERT(!retired(index));
+    MATHICGB_ASSERT(index < size());
+    MATHICGB_ASSERT(!retired(index));
     mDivisorLookup->remove(leadMonomial(index));
     std::unique_ptr<Poly> poly(mEntries[index].poly);
     mEntries[index].poly = 0;
@@ -121,33 +123,33 @@ public:
 
   // Returns true of the basis element at index has been retired.
   bool retired(size_t index) const {
-    ASSERT(index < size());
+    MATHICGB_ASSERT(index < size());
     return mEntries[index].retired;
   }
 
   // Returns the basis element polynomial at index.
   Poly& poly(size_t index) {
-    ASSERT(index < size());
-    ASSERT(!retired(index));
+    MATHICGB_ASSERT(index < size());
+    MATHICGB_ASSERT(!retired(index));
     return *mEntries[index].poly;
   }
 
   // Returns the basis element polynomial at index.
   const Poly& poly(size_t index) const {
-    ASSERT(index < size());
-    ASSERT(!retired(index));
+    MATHICGB_ASSERT(index < size());
+    MATHICGB_ASSERT(!retired(index));
     return *mEntries[index].poly;
   }
 
   const_monomial leadMonomial(size_t index) const {
-    ASSERT(index < size());
-    ASSERT(!retired(index));
+    MATHICGB_ASSERT(index < size());
+    MATHICGB_ASSERT(!retired(index));
     return poly(index).getLeadMonomial();
   }
 
   coefficient leadCoefficient(size_t index) const {
-    ASSERT(index < size());
-    ASSERT(!retired(index));
+    MATHICGB_ASSERT(index < size());
+    MATHICGB_ASSERT(!retired(index));
     return poly(index).getLeadCoefficient();
   }
 
@@ -156,16 +158,16 @@ public:
   // monomials are required to be unique among basis elements, so the case
   // of several equal lead monomials does not occur.
   bool leadMinimal(size_t index) const {
-    ASSERT(index < size());
-    ASSERT(!retired(index));
+    MATHICGB_ASSERT(index < size());
+    MATHICGB_ASSERT(!retired(index));
     MATHICGB_SLOW_ASSERT(mEntries[index].leadMinimal == leadMinimalSlow(index));
     return mEntries[index].leadMinimal;
   }
 
-  // Returns true m is not divisible by the lead monomial of any
+  // Returns true if m is not divisible by the lead monomial of any
   // basis element. Equality counts as divisibility.
   bool leadMinimal(const Poly& poly) const {
-    ASSERT(&poly != 0);
+    MATHICGB_ASSERT(&poly != 0);
     return mDivisorLookup->divisor(poly.getLeadMonomial()) !=
       static_cast<size_t>(-1);
   }
@@ -179,8 +181,8 @@ public:
 
   // Returns the basis element polynomial at index.
   const Poly& basisElement(size_t index) const {
-    ASSERT(index < size());
-    ASSERT(!retired(index));
+    MATHICGB_ASSERT(index < size());
+    MATHICGB_ASSERT(!retired(index));
     return *mEntries[index].poly;
   }
 
@@ -193,42 +195,42 @@ public:
   size_t getMemoryUse() const;
 
   void usedAsStart(size_t index) const {
-    ASSERT(index < size());
+    MATHICGB_ASSERT(index < size());
     ++mEntries[index].usedAsStartCount;
   }
 
   unsigned long long usedAsStartCount(size_t index) const {
-    ASSERT(index < size());
+    MATHICGB_ASSERT(index < size());
     return mEntries[index].usedAsStartCount;
   }
 
   void usedAsReducer(size_t index) const {
-    ASSERT(index < size());
+    MATHICGB_ASSERT(index < size());
     ++mEntries[index].usedAsReducerCount;
   }
 
   unsigned long long usedAsReducerCount(size_t index) const {
-    ASSERT(index < size());
+    MATHICGB_ASSERT(index < size());
     return mEntries[index].usedAsReducerCount;
   }
 
   void wasPossibleReducer(size_t index) const {
-    ASSERT(index < size());
+    MATHICGB_ASSERT(index < size());
     ++mEntries[index].possibleReducerCount;
   }
 
   unsigned long long wasPossibleReducerCount(size_t index) const {
-    ASSERT(index < size());
+    MATHICGB_ASSERT(index < size());
     return mEntries[index].possibleReducerCount;
   }
 
   void wasNonSignatureReducer(size_t index) const {
-    ASSERT(index < size());
+    MATHICGB_ASSERT(index < size());
     ++mEntries[index].nonSignatureReducerCount;
   }
 
   unsigned long long wasNonSignatureReducerCount(size_t index) const {
-    ASSERT(index < size());
+    MATHICGB_ASSERT(index < size());
     return mEntries[index].nonSignatureReducerCount;
   }
 
diff --git a/src/mathicgb/PolyRing.hpp b/src/mathicgb/PolyRing.hpp
index c69d6e1..9b94c3c 100755
--- a/src/mathicgb/PolyRing.hpp
+++ b/src/mathicgb/PolyRing.hpp
@@ -669,7 +669,8 @@ inline void PolyRing::monomialDivideToNegative(ConstMonomial a,
     result[i] = a[i] - b[i];
   MATHICGB_ASSERT(result[mHashIndex] == a[mHashIndex] - b[mHashIndex]);
   MATHICGB_ASSERT(!hashValid(a) || !hashValid(b) || hashValid(result));
-  MATHICGB_ASSERT(computeHashValue(result) == computeHashValue(a) - computeHashValue(b));
+  MATHICGB_ASSERT(computeHashValue(result) ==
+                  computeHashValue(a) - computeHashValue(b));
 }
 
 inline bool PolyRing::monomialRelativelyPrime(ConstMonomial a, 
diff --git a/src/mathicgb/Reducer.hpp b/src/mathicgb/Reducer.hpp
index 7f45b2c..bd0bab4 100755
--- a/src/mathicgb/Reducer.hpp
+++ b/src/mathicgb/Reducer.hpp
@@ -36,6 +36,14 @@ public:
   virtual std::unique_ptr<Poly> classicReduceSPoly
   (const Poly& a, const Poly& b, const PolyBasis& basis) = 0;
 
+  /** Clasically reduces the S-polynomial of these pairs. May or may
+      not also interreduce these to some extent. Polynomials that are
+      reduced to zero are not put into reducedOut. */
+  virtual void classicReduceSPolyGroup
+  (std::vector<std::pair<size_t, size_t> >& spairs,
+   const PolyBasis& basis,
+   std::vector<std::unique_ptr<Poly> >& reducedOut) = 0;
+
   /** Regular reduce multiple*basisElement in signature sig by the
     basis elements in basis. Returns null (0) if multiple*basisElement
     is not regular top reducible -- this indicates a singular
diff --git a/src/mathicgb/SPairs.cpp b/src/mathicgb/SPairs.cpp
index 01eccd4..aafe98c 100755
--- a/src/mathicgb/SPairs.cpp
+++ b/src/mathicgb/SPairs.cpp
@@ -147,7 +147,7 @@ SPairs::ClassicPairTriangle::ClassicPairTriangle(const PolyBasis& basis, size_t
   mBasis(basis) {}
 
 bool SPairs::simpleBuchbergerLcmCriterion
-  (size_t a, size_t b, const_monomial lcmAB) const
+(size_t a, size_t b, const_monomial lcmAB) const
 {
   ASSERT(a < mBasis.size());
   ASSERT(b < mBasis.size());
@@ -155,7 +155,7 @@ bool SPairs::simpleBuchbergerLcmCriterion
   ASSERT(!mBasis.retired(a));
   ASSERT(!mBasis.retired(b));
   ASSERT(mRing.monomialIsLeastCommonMultipleNoWeights
-    (mBasis.leadMonomial(a), mBasis.leadMonomial(b), lcmAB));
+         (mBasis.leadMonomial(a), mBasis.leadMonomial(b), lcmAB));
   ASSERT(mEliminated.columnCount() == mBasis.size());
 
   class Criterion : public DivisorLookup::EntryOutput {
@@ -173,8 +173,6 @@ bool SPairs::simpleBuchbergerLcmCriterion
       ASSERT(index < mBasis.size());
       ASSERT(!applies()); // should have stopped search in this case
       ASSERT(mRing.monomialIsDivisibleBy(mLcmAB, mBasis.leadMonomial(index)));
-      if (!mBasis.leadMinimal(index))
-        return true;
       if (index == mA || index == mB)
         return true;
       mAlmostApplies = true;
@@ -186,12 +184,12 @@ bool SPairs::simpleBuchbergerLcmCriterion
       const_monomial leadB = mBasis.leadMonomial(mB);
       const_monomial leadC = mBasis.leadMonomial(index);
       if (!mSPairs.eliminated(index, mA) &&
-        !mRing.monomialHasStrictlyLargerExponent(leadB, leadC, leadA))
+          !mRing.monomialHasStrictlyLargerExponent(leadB, leadC, leadA))
         return true;
 
       // check lcm(b,index) != lcm(a,b)
       if (!mSPairs.eliminated(index, mB) &&
-        !mRing.monomialHasStrictlyLargerExponent(leadA, leadC, leadB))
+          !mRing.monomialHasStrictlyLargerExponent(leadA, leadC, leadB))
         return true;
 
       mHit = index;
@@ -240,13 +238,13 @@ bool SPairs::simpleBuchbergerLcmCriterion
       // test I did.
       size_t cacheB = mBuchbergerLcmHitCache[b];
       if (!applies && !mBasis.retired(cacheB) &&
-        mRing.monomialIsDivisibleBy
+          mRing.monomialIsDivisibleBy
           (criterion.lcmAB(), mBasis.leadMonomial(cacheB)))
         applies = !criterion.Criterion::proceed(cacheB);
 
       size_t cacheA = mBuchbergerLcmHitCache[a];
       if (!applies && !mBasis.retired(cacheA) &&
-        mRing.monomialIsDivisibleBy
+          mRing.monomialIsDivisibleBy
           (criterion.lcmAB(), mBasis.leadMonomial(cacheA))) {
         applies = !criterion.Criterion::proceed(cacheA);
         if (applies)
@@ -255,10 +253,10 @@ bool SPairs::simpleBuchbergerLcmCriterion
     }
     if (applies)
       {
-	if (mStats.late)
-	  ++mStats.buchbergerLcmCacheHitsLate;
-	else
-	  ++mStats.buchbergerLcmCacheHits;
+        if (mStats.late)
+          ++mStats.buchbergerLcmCacheHitsLate;
+        else
+          ++mStats.buchbergerLcmCacheHits;
       }
     else {
       ASSERT(!criterion.applies());
@@ -278,9 +276,9 @@ bool SPairs::simpleBuchbergerLcmCriterion
   if (applies)
     {
       if (mStats.late)
-	++mStats.buchbergerLcmSimpleHitsLate;
+        ++mStats.buchbergerLcmSimpleHitsLate;
       else
-	++mStats.buchbergerLcmSimpleHits;
+        ++mStats.buchbergerLcmSimpleHits;
     }
 
   ASSERT(applies == simpleBuchbergerLcmCriterionSlow(a, b));
@@ -303,7 +301,7 @@ bool SPairs::simpleBuchbergerLcmCriterionSlow(size_t a, size_t b) const {
   size_t stop = mBasis.size();
   size_t i = 0;
   for (; i < stop; ++i) {
-    if (mBasis.retired(i) || !mBasis.leadMinimal(i))
+    if (mBasis.retired(i))
       continue;
     if (!mRing.monomialIsDivisibleBy(lcmAB, mBasis.leadMonomial(i)))
       continue;
diff --git a/src/mathicgb/TypicalReducer.cpp b/src/mathicgb/TypicalReducer.cpp
index bb276bf..a2be4ba 100755
--- a/src/mathicgb/TypicalReducer.cpp
+++ b/src/mathicgb/TypicalReducer.cpp
@@ -133,6 +133,18 @@ std::unique_ptr<Poly> TypicalReducer::classicReduceSPoly(
   return std::move(reduced);
 }
 
+void TypicalReducer::classicReduceSPolyGroup
+(std::vector<std::pair<size_t, size_t> >& spairs,
+ const PolyBasis& basis,
+ std::vector<std::unique_ptr<Poly> >& reducedOut) {
+  for (auto it = spairs.begin(); it != spairs.end(); ++it) {
+    auto reducedSPoly =
+      classicReduceSPoly(basis.poly(it->first), basis.poly(it->second), basis);
+    if (!reducedSPoly->isZero())
+      reducedOut.push_back(std::move(reducedSPoly));
+  }
+}
+
 std::unique_ptr<Poly> TypicalReducer::classicReduce
     (std::unique_ptr<Poly> result, const PolyBasis& basis) {
   const PolyRing& ring = basis.ring();
diff --git a/src/mathicgb/TypicalReducer.hpp b/src/mathicgb/TypicalReducer.hpp
index fc87db9..33846ed 100755
--- a/src/mathicgb/TypicalReducer.hpp
+++ b/src/mathicgb/TypicalReducer.hpp
@@ -33,6 +33,11 @@ public:
   virtual std::unique_ptr<Poly> classicReduceSPoly
     (const Poly& a, const Poly& b, const PolyBasis& basis);
 
+  virtual void classicReduceSPolyGroup
+  (std::vector<std::pair<size_t, size_t> >& spairs,
+   const PolyBasis& basis,
+   std::vector<std::unique_ptr<Poly> >& reducedOut);
+
 protected:
   // These are the methods that sub-classes define in order to carry
   // out sub-steps in the reduction.
diff --git a/src/test/gb-test.cpp b/src/test/gb-test.cpp
index b5834a4..9ffabe0 100755
--- a/src/test/gb-test.cpp
+++ b/src/test/gb-test.cpp
@@ -50,123 +50,146 @@ void testGB(int freeModuleOrder,
   // pict.in for details.
 #define MATHICGB_ESCAPE_MULTILINE_STRING(str) #str
   char const allPairsTests[] = MATHICGB_ESCAPE_MULTILINE_STRING(
-spairQueue	reducerType	divLookup	monTable	buchberger	postponeKoszul	useBaseDivisors	autoTailReduce	autoTopReduce	preferSparseReducers	useSingularCriterionEarly
-2	12	1	1	0	0	0	0	0	1	0
-1	6	2	2	0	1	1	0	0	0	1
-0	6	2	0	1	0	0	1	1	0	0
-1	7	1	2	1	0	0	1	1	1	0
-0	15	1	0	0	1	1	0	0	1	1
-2	8	2	1	0	0	1	0	0	0	1
-2	4	1	1	1	0	0	0	1	0	0
-3	19	2	1	1	0	0	1	0	1	0
-1	11	1	1	1	0	0	1	0	1	0
-0	14	1	1	1	0	0	1	0	0	0
-1	9	2	0	1	0	0	1	1	0	0
-1	15	2	1	1	0	0	1	1	0	0
-2	22	1	0	1	0	0	1	0	1	0
-3	14	1	0	0	1	1	0	0	1	1
-2	6	1	1	1	0	0	1	1	1	0
-0	10	2	2	1	0	0	0	1	1	0
-2	7	2	1	0	1	0	0	0	0	1
-2	14	2	2	1	0	0	1	1	1	0
-3	20	1	2	1	0	0	0	1	0	0
-0	8	1	2	1	0	0	1	1	1	0
-0	1	1	1	0	1	1	0	0	1	0
-3	22	2	1	0	1	1	0	0	0	1
-1	10	1	1	0	1	1	0	0	0	1
-2	11	2	0	0	1	1	0	0	0	1
-0	25	2	0	1	0	0	0	1	0	0
-2	15	1	2	0	0	1	0	0	0	1
-2	21	2	0	0	1	0	0	0	1	1
-3	2	2	1	0	1	0	0	0	0	0
-2	5	1	0	0	1	1	0	0	0	1
-1	12	2	0	0	1	1	0	0	0	1
-0	19	1	2	0	1	1	0	0	0	1
-3	17	1	0	0	1	1	0	0	0	0
-1	14	2	2	0	0	0	0	0	1	1
-3	1	2	0	0	0	0	0	0	0	1
-2	0	1	1	1	0	0	1	0	1	0
-2	20	2	0	0	1	1	0	0	1	1
-0	23	1	2	1	0	0	1	0	1	0
-0	0	2	0	0	1	1	0	0	0	1
-2	2	1	2	0	0	1	0	0	1	1
-2	16	2	0	1	0	0	0	1	0	0
-0	20	2	1	1	0	0	1	0	0	0
-1	3	2	2	0	0	1	0	0	1	1
-0	24	2	0	1	0	0	1	0	0	0
-3	7	2	0	0	1	1	0	0	1	1
-1	0	1	2	0	1	0	0	0	0	1
-2	23	2	1	0	1	1	0	0	0	1
-1	18	2	1	0	1	0	0	0	1	1
-1	20	1	1	0	0	0	0	0	0	1
-2	25	1	1	0	1	1	0	0	1	1
-3	9	1	1	0	1	1	0	0	1	1
-1	23	2	0	0	1	1	0	0	0	1
-2	17	2	2	0	0	0	0	0	1	1
-0	21	1	2	1	0	0	1	1	0	0
-3	3	1	1	1	0	0	1	1	0	0
-2	1	1	2	1	0	0	1	1	0	0
-1	5	2	2	1	0	0	1	1	1	0
-3	21	1	1	1	0	0	1	0	1	0
-3	6	1	0	0	0	0	0	0	1	1
-0	9	2	2	1	0	0	0	1	1	0
-3	11	2	2	0	0	0	0	0	1	1
-3	10	1	0	1	0	0	1	0	1	0
-2	19	1	0	1	0	0	1	1	1	0
-0	12	2	2	1	0	0	1	1	1	0
-0	2	2	0	0	1	0	0	0	0	1
-1	25	1	2	1	0	0	1	1	0	0
-1	16	1	2	0	1	1	0	0	1	1
-1	4	2	2	0	1	1	0	0	1	1
-3	25	1	2	0	1	1	0	0	0	1
-1	8	1	0	1	0	0	1	0	0	0
-2	18	1	0	1	0	0	1	1	0	0
-0	4	2	0	1	0	0	1	1	0	0
-0	18	2	2	0	1	1	0	0	1	1
-1	17	2	1	0	0	1	0	0	1	1
-1	24	1	2	0	1	1	0	0	1	1
-3	24	2	1	1	0	0	0	1	0	0
-1	19	1	2	0	0	1	0	0	0	1
-1	21	2	2	0	1	1	0	0	1	1
-3	16	2	1	0	1	0	0	0	1	1
-0	22	2	2	0	1	0	0	0	1	1
-3	0	2	2	0	1	1	0	0	0	1
-2	9	2	2	1	0	0	1	0	1	0
-3	18	1	1	0	1	0	0	0	1	1
-3	15	1	2	0	1	0	0	0	0	1
-1	1	1	1	0	1	0	0	0	1	1
-2	24	1	1	0	0	1	0	0	0	1
-2	3	2	0	0	1	1	0	0	0	1
-0	11	2	2	1	0	0	1	1	1	0
-3	13	2	1	1	0	0	1	0	0	0
-3	12	1	1	1	0	0	1	1	1	0
-0	5	2	1	1	0	0	1	0	0	0
-1	22	1	0	1	0	0	0	1	0	0
-2	13	1	2	0	1	1	0	0	1	1
-0	16	2	0	0	0	0	0	0	0	1
-0	17	2	2	0	0	0	0	0	0	1
-1	2	1	1	1	0	0	1	1	0	0
-3	23	2	0	0	1	1	0	0	0	1
-0	7	1	0	0	1	0	0	0	1	1
-1	13	1	0	0	1	1	0	0	0	1
-2	10	1	0	0	1	0	0	0	1	1
-0	13	1	0	1	0	0	0	1	0	0
-3	4	1	0	0	0	0	0	0	1	1
-2	23	1	0	1	0	0	1	1	1	0
-3	5	1	0	0	1	0	0	0	0	1
-0	3	1	2	0	1	0	0	0	1	1
-3	16	1	1	1	0	0	1	1	0	0
-0	17	1	0	1	0	0	1	1	1	0
-3	8	1	2	0	1	1	0	0	0	1
-2	0	2	0	1	0	0	0	1	0	0
+spairQueue	reducerType	divLookup	monTable	buchberger	postponeKoszul	useBaseDivisors	autoTailReduce	autoTopReduce	preferSparseReducers	useSingularCriterionEarly	sPairGroupSize
+1	19	2	2	1	0	0	0	0	0	0	1
+2	2	1	0	0	1	1	0	0	1	1	1
+0	14	1	1	1	0	0	1	1	1	0	2
+3	7	2	1	0	0	1	0	0	0	1	10
+2	23	2	0	1	0	0	1	1	0	0	0
+3	8	1	2	1	0	0	1	1	1	0	10
+0	1	1	2	0	1	0	0	0	0	1	10
+1	11	2	1	1	0	0	1	1	1	0	1
+1	15	1	0	1	0	0	1	0	1	0	10
+1	13	2	2	0	1	1	0	0	1	1	0
+3	14	2	1	0	1	1	0	0	0	1	0
+0	12	2	0	0	1	1	0	0	0	1	2
+2	4	2	2	1	0	0	0	1	0	0	10
+2	21	1	2	1	0	0	1	0	1	0	2
+2	3	2	1	1	0	0	1	1	1	0	10
+3	1	2	0	1	0	0	1	1	1	0	100
+3	13	1	0	1	0	0	1	1	0	0	2
+3	10	2	0	0	1	1	0	0	0	0	10
+0	6	1	0	0	0	1	0	0	1	1	0
+1	24	1	2	1	0	0	0	1	0	0	2
+1	12	1	2	0	0	0	0	0	0	1	100
+1	8	2	0	0	1	1	0	0	0	1	2
+2	22	1	1	1	0	0	0	1	0	0	100
+0	2	2	1	1	0	0	1	1	0	0	100
+0	13	2	1	0	1	1	0	0	0	1	100
+0	8	1	1	0	1	0	0	0	0	1	0
+0	9	1	0	0	1	1	0	0	1	1	100
+3	9	2	2	1	0	0	1	1	0	0	1
+0	22	2	2	0	1	1	0	0	1	1	1
+2	6	2	2	1	0	0	1	1	0	0	2
+1	5	1	1	0	0	1	0	0	1	1	0
+1	23	1	2	0	1	1	0	0	1	1	1
+3	15	2	1	0	1	1	0	0	0	1	2
+2	17	2	0	0	0	0	0	0	0	1	10
+3	20	1	2	1	0	0	0	1	0	0	0
+3	0	1	2	1	0	0	1	0	1	0	0
+0	21	2	0	0	1	1	0	0	0	1	10
+2	0	2	1	0	1	1	0	0	0	1	100
+0	4	1	0	0	1	1	0	0	1	1	1
+1	25	2	0	0	1	0	0	0	0	1	2
+0	16	1	2	0	0	0	0	0	0	0	2
+0	17	1	2	1	0	0	1	1	1	0	100
+3	21	2	1	0	0	1	0	0	0	1	1
+0	20	2	0	0	1	1	0	0	1	1	10
+2	14	1	2	0	0	0	0	0	1	1	10
+0	0	1	0	1	0	0	1	1	1	0	10
+1	1	1	1	0	1	1	0	0	1	1	1
+1	2	2	2	0	0	0	0	0	1	1	2
+0	25	1	2	1	0	0	1	1	1	0	10
+3	5	2	0	1	0	0	1	1	0	0	1
+0	19	1	0	0	1	1	0	0	1	1	0
+2	24	2	0	0	1	1	0	0	1	1	100
+3	19	1	1	0	1	1	0	0	0	1	10
+2	9	1	1	0	1	0	0	0	1	1	0
+3	12	1	1	1	0	0	1	1	1	0	10
+1	10	1	1	0	0	0	0	0	1	1	1
+2	12	2	0	1	0	0	1	0	0	0	1
+1	18	1	1	0	0	1	0	0	0	1	2
+3	23	2	1	1	0	0	1	0	1	0	100
+2	10	2	2	1	0	0	1	1	1	0	0
+0	12	1	2	0	0	1	0	0	0	1	0
+2	15	1	2	0	0	1	0	0	0	1	1
+0	15	1	0	1	0	0	1	1	0	0	100
+0	24	2	1	0	0	0	0	0	1	1	10
+2	1	2	2	1	0	0	0	1	0	0	2
+3	22	1	0	0	1	1	0	0	0	1	2
+2	19	2	0	0	1	1	0	0	0	1	2
+1	22	1	1	1	0	0	1	0	0	0	10
+1	16	2	1	0	1	1	0	0	1	1	10
+1	20	2	1	1	0	0	1	0	1	0	2
+1	4	2	1	1	0	0	1	1	0	0	100
+0	23	1	2	0	1	1	0	0	0	1	2
+1	6	2	1	1	0	0	1	0	1	0	100
+3	17	1	1	1	0	0	0	1	0	0	1
+2	16	2	0	1	0	0	1	1	1	0	100
+1	9	1	0	1	0	0	1	0	1	0	2
+2	13	1	0	0	1	1	0	0	0	1	1
+3	2	2	1	0	0	1	0	0	0	1	0
+2	25	2	1	0	1	1	0	0	0	1	0
+3	3	1	2	0	1	1	0	0	0	1	0
+3	11	1	0	0	1	1	0	0	0	1	2
+1	0	2	0	1	0	0	1	0	1	0	2
+2	11	1	2	1	0	0	1	1	0	0	10
+1	14	2	0	0	1	0	0	0	0	0	1
+1	2	1	1	0	1	0	0	0	1	1	10
+3	16	2	2	0	1	1	0	0	0	1	0
+0	14	2	1	0	1	1	0	0	1	1	100
+2	8	1	0	0	1	0	0	0	0	1	1
+0	8	1	2	1	0	0	0	0	0	0	100
+1	7	1	2	1	0	0	1	1	1	0	0
+0	3	2	0	0	1	0	0	0	0	0	1
+2	18	2	2	1	0	0	1	1	1	0	10
+1	17	1	0	1	0	0	0	1	0	0	0
+3	18	2	0	1	0	0	0	1	1	0	100
+3	16	2	0	0	0	1	0	0	1	1	1
+0	13	1	2	1	0	0	1	0	0	0	10
+0	5	2	2	0	1	1	0	0	1	1	2
+3	6	2	2	0	1	0	0	0	1	1	10
+2	7	2	0	0	1	1	0	0	0	1	2
+2	5	1	0	0	1	1	0	0	0	1	10
+0	19	2	2	1	0	0	1	1	1	0	100
+3	4	2	2	0	1	1	0	0	1	1	0
+3	15	1	0	1	0	0	1	1	1	0	0
+2	20	2	1	0	1	1	0	0	0	1	1
+3	17	2	0	0	1	1	0	0	0	1	2
+1	21	1	1	1	0	0	0	1	1	0	0
+3	4	2	0	1	0	0	0	1	1	0	2
+3	5	1	2	0	1	1	0	0	1	1	100
+0	7	1	1	0	0	1	0	0	0	1	1
+0	18	2	1	1	0	0	1	1	1	0	0
+0	10	2	2	1	0	0	1	0	1	0	100
+2	7	1	0	0	1	1	0	0	1	1	100
+1	10	1	1	1	0	0	1	1	1	0	2
+3	25	1	1	1	0	0	1	0	1	0	100
+1	0	1	2	0	1	1	0	0	1	0	1
+1	22	1	1	1	0	0	0	1	0	0	0
+3	24	1	2	1	0	0	1	1	0	0	0
+2	25	1	0	0	1	1	0	0	1	1	1
+1	21	1	0	0	0	0	0	0	0	1	100
+1	9	2	2	1	0	0	0	0	1	0	10
+1	18	1	0	0	1	0	0	0	0	1	1
+1	3	1	0	0	0	0	0	0	0	1	2
+2	6	1	1	0	0	1	0	0	1	1	1
+0	24	1	2	1	0	0	1	0	1	0	1
+0	11	1	1	0	1	0	0	0	1	1	100
+0	3	2	2	1	0	0	0	1	0	0	100
+2	11	2	2	1	0	0	1	0	0	0	0
+1	23	1	2	1	0	0	0	1	0	0	10
+2	20	2	2	0	1	0	0	0	1	0	100
+2	1	1	0	1	0	0	1	1	1	0	0
 );
   std::istringstream tests(allPairsTests);
   // skip the initial line with the parameter names.
   {
-      char const* params[] = {
-        "spairQueue", "reducerType", "divLookup", "monTable",
-        "buchberger", "postponeKoszul", "useBaseDivisors", "autoTailReduce",
-        "autoTopReduce", "preferSparseReducers", "useSingularCriterionEarly"};
+    char const* params[] = {
+      "spairQueue", "reducerType", "divLookup", "monTable",
+      "buchberger", "postponeKoszul", "useBaseDivisors", "autoTailReduce",
+      "autoTopReduce", "preferSparseReducers", "useSingularCriterionEarly",
+      "sPairGroupSize"};
 
     std::string paramName;
     size_t const paramCount = sizeof(params) / sizeof(*params);
@@ -233,6 +256,10 @@ spairQueue	reducerType	divLookup	monTable	buchberger	postponeKoszul	useBaseDivis
     MATHICGB_ASSERT(0 <= useSingularCriterionEarly);
     MATHICGB_ASSERT(useSingularCriterionEarly <= 1);
 
+    int sPairGroupSize;
+    tests >> sPairGroupSize;
+    MATHICGB_ASSERT(0 <= sPairGroupSize);
+
     // Rule out combinations of parameter values that do not make sense.
     // These are asserts because pict should have already removed these
     // combinations.
@@ -251,9 +278,10 @@ spairQueue	reducerType	divLookup	monTable	buchberger	postponeKoszul	useBaseDivis
 
     if (buchberger) {
       BuchbergerAlg alg(
-        *I, freeModuleOrder, Reducer::reducerType(reducerType), divLookup, preferSparseReducers, spairQueue);
+                        *I, freeModuleOrder, Reducer::reducerType(reducerType), divLookup, preferSparseReducers, spairQueue);
       alg.setUseAutoTopReduction(autoTopReduce);
       alg.setUseAutoTailReduction(autoTailReduce);
+      alg.setSPairGroupSize(sPairGroupSize);
       alg.computeGrobnerBasis();
       std::unique_ptr<Ideal> initialIdeal =
         alg.basis().initialIdeal();
@@ -263,7 +291,7 @@ spairQueue	reducerType	divLookup	monTable	buchberger	postponeKoszul	useBaseDivis
     } else {
       SignatureGB basis
         (*I, freeModuleOrder, Reducer::reducerType(reducerType),
-          divLookup, monTable, postponeKoszul, useBaseDivisors, preferSparseReducers, useSingularCriterionEarly, spairQueue);
+         divLookup, monTable, postponeKoszul, useBaseDivisors, preferSparseReducers, useSingularCriterionEarly, spairQueue);
       basis.computeGrobnerBasis();
       EXPECT_EQ(sigBasisStr, toString(basis.getGB(), 1))
         << reducerType << ' ' << divLookup << ' '
diff --git a/src/test/pict.in b/src/test/pict.in
index e21ca1b..59e0e71 100755
--- a/src/test/pict.in
+++ b/src/test/pict.in
@@ -33,6 +33,7 @@ autoTailReduce: 0,1
 autoTopReduce: 0,1
 preferSparseReducers: 0,1
 useSingularCriterionEarly: 0, 1
+sPairGroupSize: 0, 1, 2, 10, 100
 
 ##############################################################
 # PICT submodels go here.

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/mathicgb.git



More information about the debian-science-commits mailing list