[mathicgb] 138/393: Added new matrix construction code that decouples left/right splitting from the initial matrix construction. I want this to be as fast as the previous code, so the previous code is still there for now for comparison. The new code can be called using reducer 26.

Doug Torrance dtorrance-guest at moszumanska.debian.org
Fri Apr 3 15:58:49 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 f3dfcb30eb01c737d4b006ddeff28b7c1aea4ec7
Author: Bjarke Hammersholt Roune <bjarkehr.code at gmail.com>
Date:   Thu Jan 24 19:55:25 2013 +0100

    Added new matrix construction code that decouples left/right splitting from the initial matrix construction. I want this to be as fast as the previous code, so the previous code is still there for now for comparison. The new code can be called using reducer 26.
---
 build/vs12/mathicgb-lib/mathicgb-lib.vcxproj       |   2 +
 .../vs12/mathicgb-lib/mathicgb-lib.vcxproj.filters |   6 +
 src/cli/GBAction.cpp                               |  11 +-
 src/mathicgb/F4MatrixBuilder2.cpp                  | 581 +++++++++++++++++++++
 src/mathicgb/F4MatrixBuilder2.hpp                  | 156 ++++++
 src/mathicgb/F4Reducer.cpp                         |  44 +-
 src/mathicgb/F4Reducer.hpp                         |   8 +-
 src/mathicgb/MonomialMap.hpp                       |   2 +-
 src/mathicgb/QuadMatrix.cpp                        |   4 +
 src/mathicgb/Reducer.cpp                           |  12 +-
 src/mathicgb/Reducer.hpp                           |   3 +-
 src/mathicgb/SparseMatrix.hpp                      |  65 +++
 src/test/F4MatrixBuilder.cpp                       |  12 +-
 src/test/gb-test.cpp                               | 276 +++++-----
 src/test/pict.in                                   |   8 +-
 15 files changed, 1025 insertions(+), 165 deletions(-)

diff --git a/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj b/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj
index 87369e7..03166b7 100755
--- a/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj
+++ b/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj
@@ -446,6 +446,7 @@
     <ClCompile Include="..\..\..\src\mathicgb\ChainedHashTable.cpp" />
     <ClCompile Include="..\..\..\src\mathicgb\DivisorLookup.cpp" />
     <ClCompile Include="..\..\..\src\mathicgb\F4MatrixBuilder.cpp" />
+    <ClCompile Include="..\..\..\src\mathicgb\F4MatrixBuilder2.cpp" />
     <ClCompile Include="..\..\..\src\mathicgb\F4MatrixReducer.cpp" />
     <ClCompile Include="..\..\..\src\mathicgb\F4Reducer.cpp" />
     <ClCompile Include="..\..\..\src\mathicgb\FreeModuleOrder.cpp" />
@@ -487,6 +488,7 @@
     <ClInclude Include="..\..\..\src\mathicgb\DivisorLookup.hpp" />
     <ClInclude Include="..\..\..\src\mathicgb\DivLookup.hpp" />
     <ClInclude Include="..\..\..\src\mathicgb\F4MatrixBuilder.hpp" />
+    <ClInclude Include="..\..\..\src\mathicgb\F4MatrixBuilder2.hpp" />
     <ClInclude Include="..\..\..\src\mathicgb\F4MatrixReducer.hpp" />
     <ClInclude Include="..\..\..\src\mathicgb\F4Reducer.hpp" />
     <ClInclude Include="..\..\..\src\mathicgb\FixedSizeMonomialMap.h" />
diff --git a/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj.filters b/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj.filters
index 1b55392..fd74cd5 100755
--- a/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj.filters
+++ b/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj.filters
@@ -126,6 +126,9 @@
     <ClCompile Include="..\..\..\src\mathicgb\LogDomain.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\..\src\mathicgb\F4MatrixBuilder2.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\..\src\mathicgb\BjarkeGeobucket.hpp">
@@ -290,5 +293,8 @@
     <ClInclude Include="..\..\..\src\mathicgb\LogDomainSet.hpp">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\..\src\mathicgb\F4MatrixBuilder2.hpp">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/cli/GBAction.cpp b/src/cli/GBAction.cpp
index 220c7b9..0e91719 100644
--- a/src/cli/GBAction.cpp
+++ b/src/cli/GBAction.cpp
@@ -72,10 +72,15 @@ void GBAction::performAction() {
   // run algorithm
   const auto reducerType = Reducer::reducerType(mGBParams.mReducer.value());
   std::unique_ptr<Reducer> reducer;
-  if (reducerType != Reducer::Reducer_F4)
+  if (
+    reducerType != Reducer::Reducer_F4_Old &&
+    reducerType != Reducer::Reducer_F4_New
+  ) {
     reducer = Reducer::makeReducer(reducerType, *ring);
-  else {
-    auto f4Reducer = make_unique<F4Reducer>(*ring);
+  } else {
+    const auto type = reducerType == Reducer::Reducer_F4_Old ?
+      F4Reducer::OldType : F4Reducer::NewType;
+    auto f4Reducer = make_unique<F4Reducer>(*ring, type);
     if (mMinMatrixToStore.value() > 0)
       f4Reducer->writeMatricesTo(projectName, mMinMatrixToStore);
     reducer = std::move(f4Reducer);
diff --git a/src/mathicgb/F4MatrixBuilder2.cpp b/src/mathicgb/F4MatrixBuilder2.cpp
new file mode 100755
index 0000000..7db04b0
--- /dev/null
+++ b/src/mathicgb/F4MatrixBuilder2.cpp
@@ -0,0 +1,581 @@
+#include "stdinc.h"
+#include "F4MatrixBuilder2.hpp"
+
+#include <tbb/tbb.h>
+
+MATHICGB_NO_INLINE
+std::pair<F4MatrixBuilder2::ColIndex, ConstMonomial>
+F4MatrixBuilder2::findOrCreateColumn(
+  const const_monomial monoA,
+  const const_monomial monoB,
+  TaskFeeder& feeder
+) {
+  MATHICGB_ASSERT(!monoA.isNull());
+  MATHICGB_ASSERT(!monoB.isNull());
+  const auto col = ColReader(mMap).findProduct(monoA, monoB);
+  if (col.first != 0)
+    return std::make_pair(*col.first, col.second);
+  return createColumn(monoA, monoB, feeder);
+}
+
+MATHICGB_INLINE
+std::pair<F4MatrixBuilder2::ColIndex, ConstMonomial>
+F4MatrixBuilder2::findOrCreateColumn(
+  const const_monomial monoA,
+  const const_monomial monoB,
+  const ColReader& colMap,
+  TaskFeeder& feeder
+) {
+  MATHICGB_ASSERT(!monoA.isNull());
+  MATHICGB_ASSERT(!monoB.isNull());
+  const auto col = colMap.findProduct(monoA, monoB);
+  if (col.first == 0)
+    return findOrCreateColumn(monoA, monoB, feeder);
+  return std::make_pair(*col.first, col.second);
+}
+
+MATHICGB_NO_INLINE
+void F4MatrixBuilder2::createTwoColumns(
+  const const_monomial monoA1,
+  const const_monomial monoA2,
+  const const_monomial monoB,
+  TaskFeeder& feeder
+) {
+  createColumn(monoA1, monoB, feeder);
+  createColumn(monoA2, monoB, feeder);
+}
+
+F4MatrixBuilder2::F4MatrixBuilder2(
+  const PolyBasis& basis,
+  const size_t memoryQuantum
+):
+  mMemoryQuantum(memoryQuantum),
+  mTmp(basis.ring().allocMonomial()),
+  mBasis(basis),
+  mMap(basis.ring()),
+  mLeftColCount(0),
+  mRightColCount(0)
+{
+  // This assert has to be _NO_ASSUME since otherwise the compiler will assume
+  // that the error checking branch here cannot be taken and optimize it away.
+  const Scalar maxScalar = std::numeric_limits<Scalar>::max();
+  MATHICGB_ASSERT_NO_ASSUME(ring().charac() <= maxScalar);
+  if (ring().charac() > maxScalar)
+    mathic::reportInternalError("F4MatrixBuilder2: too large characteristic.");
+}
+
+void F4MatrixBuilder2::addSPolynomialToMatrix(
+  const Poly& polyA,
+  const Poly& polyB
+) {
+  MATHICGB_ASSERT(!polyA.isZero());
+  MATHICGB_ASSERT(polyA.isMonic());
+  MATHICGB_ASSERT(!polyB.isZero());
+  MATHICGB_ASSERT(polyB.isMonic());
+
+  RowTask task;
+  task.addToTop = false;
+  task.poly = &polyA;
+  task.sPairPoly = &polyB;
+  mTodo.push_back(task);
+}
+
+void F4MatrixBuilder2::addPolynomialToMatrix(const Poly& poly) {
+  if (poly.isZero())
+    return;
+
+  RowTask task = {};
+  task.addToTop = false;
+  task.poly = &poly;
+  mTodo.push_back(task);
+}
+
+void F4MatrixBuilder2::addPolynomialToMatrix
+(const_monomial multiple, const Poly& poly) {
+  MATHICGB_ASSERT(ring().hashValid(multiple));
+  if (poly.isZero())
+    return;
+
+  RowTask task = {};
+  task.addToTop = false;
+  task.poly = &poly;
+  task.desiredLead = ring().allocMonomial();
+  ring().monomialMult(poly.getLeadMonomial(), multiple, task.desiredLead);
+  MATHICGB_ASSERT(ring().hashValid(task.desiredLead));
+
+  MATHICGB_ASSERT(task.sPairPoly == 0);
+  mTodo.push_back(task);
+}
+
+void F4MatrixBuilder2::buildMatrixAndClear(QuadMatrix& quadMatrix) {
+  if (mTodo.empty()) {
+    quadMatrix = QuadMatrix();
+    quadMatrix.ring = &ring();
+    return;
+  }
+
+  // todo: prefer sparse/old reducers among the inputs.
+
+  // Process pending rows until we are done. Note that the methods
+  // we are calling here can add more pending items.
+
+  struct ThreadData {
+    SparseMatrix topMatrix;
+    SparseMatrix bottomMatrix;
+    monomial tmp1;
+    monomial tmp2;
+  };
+
+  tbb::enumerable_thread_specific<ThreadData> threadData([&](){  
+    ThreadData data = {
+      SparseMatrix(mMemoryQuantum),
+      SparseMatrix(mMemoryQuantum)
+    };
+    {
+      tbb::mutex::scoped_lock guard(mCreateColumnLock);
+      data.tmp1 = ring().allocMonomial();
+      data.tmp2 = ring().allocMonomial();
+    }
+    return std::move(data);
+  });
+
+  tbb::parallel_do(mTodo.begin(), mTodo.end(),
+    [&](const RowTask& task, TaskFeeder& feeder)
+  {
+    auto& data = threadData.local();
+    const auto& poly = *task.poly;
+
+    if (task.sPairPoly != 0) {
+      MATHICGB_ASSERT(!task.addToTop);
+      ring().monomialColons(
+        poly.getLeadMonomial(),
+        task.sPairPoly->getLeadMonomial(),
+        data.tmp2,
+        data.tmp1
+      );
+      appendRowBottom
+        (&poly, data.tmp1, task.sPairPoly, data.tmp2, data.bottomMatrix, feeder);
+      MATHICGB_ASSERT(data.bottomMatrix.rowCount() == 0 || !data.bottomMatrix.emptyRow(data.bottomMatrix.rowCount() - 1));
+      return;
+    }
+    if (task.desiredLead.isNull())
+      ring().monomialSetIdentity(data.tmp1);
+    else
+      ring().monomialDivide
+        (task.desiredLead, poly.getLeadMonomial(), data.tmp1);
+    MATHICGB_ASSERT(ring().hashValid(data.tmp1));
+    if (task.addToTop) {
+      appendRowTop(data.tmp1, *task.poly, data.topMatrix, feeder);
+      MATHICGB_ASSERT(!data.topMatrix.emptyRow(data.topMatrix.rowCount() - 1));
+    } else {
+      appendRowBottom
+        (data.tmp1, false, poly.begin(), poly.end(), data.bottomMatrix, feeder);
+      MATHICGB_ASSERT(data.bottomMatrix.rowCount() == 0 || !data.bottomMatrix.emptyRow(data.bottomMatrix.rowCount() - 1));
+    }
+  });
+  MATHICGB_ASSERT(!threadData.empty()); // as mTodo empty causes early return
+
+  auto topMatrix = std::move(threadData.begin()->topMatrix);
+  auto bottomMatrix = std::move(threadData.begin()->bottomMatrix);
+  const auto end = threadData.end();
+  for (auto it = threadData.begin(); it != end; ++it) {
+    if (it != threadData.begin()) {
+      topMatrix.takeRowsFrom(std::move(it->topMatrix));
+      bottomMatrix.takeRowsFrom(std::move(it->bottomMatrix));
+    }
+    ring().freeMonomial(it->tmp1);
+    ring().freeMonomial(it->tmp2);
+  }
+  threadData.clear();
+
+  MATHICGB_ASSERT(bottomMatrix.rowCount() == mTodo.size());
+
+  // Free the monomials from all the tasks
+  const auto todoEnd = mTodo.end();
+  for (auto it = mTodo.begin(); it != todoEnd; ++it)
+    if (!it->desiredLead.isNull())
+      ring().freeMonomial(it->desiredLead);
+  mTodo.clear();
+
+  {
+    ColReader reader(mMap);
+    quadMatrix.leftColumnMonomials.swap(Monomials(mLeftColCount));
+    quadMatrix.rightColumnMonomials.swap(Monomials(mRightColCount));
+    const auto end = reader.end();
+    for (auto it = reader.begin(); it != end; ++it) {
+      const auto p = *it;
+      monomial copy = ring().allocMonomial();
+      ring().monomialCopy(p.second, copy);
+      const auto index = p.first;
+      auto translated = mTranslate[index];
+      auto& monos = translated.left ?
+        quadMatrix.leftColumnMonomials : quadMatrix.rightColumnMonomials;
+      MATHICGB_ASSERT(translated.index < monos.size());
+      MATHICGB_ASSERT(monos[translated.index].isNull());
+      monos[translated.index] = copy;
+    }
+  }
+
+  topMatrix.takeRowsFrom(std::move(bottomMatrix));
+  auto& matrix = topMatrix;
+
+#ifdef MATHICGB_DEBUG
+  for (size_t row = 0; row < matrix.rowCount(); ++row) {
+    MATHICGB_ASSERT(!matrix.emptyRow(row));
+  }
+#endif
+
+  // Decide which rows are reducers (top) and which are reducees (bottom).
+  const auto rowCount = matrix.rowCount();
+  std::vector<RowIndex> reducerRows(mLeftColCount, rowCount);
+  std::vector<RowIndex> reduceeRows;
+  for (RowIndex row = 0; row < rowCount; ++row) {
+    MATHICGB_ASSERT(!matrix.emptyRow(row));
+    // Determine leading (minimum index) left entry.
+    const auto lead = [&] {
+      MATHICGB_ASSERT(mTranslate.size() <= std::numeric_limits<ColIndex>::max());
+      const auto end = matrix.rowEnd(row);
+      for (auto it = matrix.rowBegin(row); it != end; ++it) {
+        MATHICGB_ASSERT(it.index() < mTranslate.size());
+        if (mTranslate[it.index()].left)
+          return mTranslate[it.index()].index;
+      }
+      return mLeftColCount; // no left entries at all
+    }();
+    if (!mTranslate[matrix.leadCol(row)].left) {
+      reduceeRows.push_back(row); // no left entries
+      continue;
+    }
+
+    // decide if this is a reducer or reducee row
+    if (lead == mLeftColCount) {
+      reduceeRows.push_back(row); // no left entries
+      continue;
+    }
+    auto& reducer = reducerRows[lead];
+    if (reducer == rowCount)
+      reducer = row; // row is first reducer with this lead
+    else if (matrix.entryCountInRow(reducer) > matrix.entryCountInRow(row)) {
+      reduceeRows.push_back(reducer); // row sparser (=better) reducer
+      reducer = row;
+    } else
+      reduceeRows.push_back(row);
+  }
+
+  MATHICGB_ASSERT(reducerRows.size() == mLeftColCount);
+  MATHICGB_ASSERT(reduceeRows.size() == matrix.rowCount() - mLeftColCount);
+#ifdef MATHICGB_DEBUG
+  for (size_t  i = 0; i < reducerRows.size(); ++i) {
+    const auto row = reducerRows[i];
+    MATHICGB_ASSERT(row < matrix.rowCount());
+    MATHICGB_ASSERT(!matrix.emptyRow(row));
+    MATHICGB_ASSERT(mTranslate[matrix.leadCol(row)].left);
+    MATHICGB_ASSERT(mTranslate[matrix.leadCol(row)].index == i);
+  }
+  std::vector<RowIndex> tmp;
+  tmp.insert(tmp.end(), reducerRows.begin(), reducerRows.end());
+  tmp.insert(tmp.end(), reduceeRows.begin(), reduceeRows.end());
+  std::sort(tmp.begin(), tmp.end());
+  MATHICGB_ASSERT(tmp.size() == matrix.rowCount());
+  for (size_t i = 0; i < tmp.size(); ++i) {
+    MATHICGB_ASSERT(tmp[i] == i);
+  }
+#endif
+  
+  quadMatrix.ring = &ring();
+  auto splitLeftRight = [this](
+    SparseMatrix& from,
+    const std::vector<RowIndex>& fromRows,
+    const bool makeLeftUnitary,
+    SparseMatrix& left,
+    SparseMatrix& right
+  ) {
+    left.clear();
+    right.clear();
+    const auto fromRowsEnd = fromRows.end();
+    for (
+      auto fromRowsIt = fromRows.begin();
+      fromRowsIt != fromRowsEnd;
+      ++fromRowsIt
+    ) {
+      const auto row = *fromRowsIt;
+      const auto fromEnd = from.rowEnd(row);
+      auto fromIt = from.rowBegin(row);
+      MATHICGB_ASSERT(!from.emptyRow(row));
+      if (
+        makeLeftUnitary &&
+        (!mTranslate[fromIt.index()].left || fromIt.scalar() != 1)
+      ) {
+        auto firstLeft = fromIt;
+        while (!mTranslate[firstLeft.index()].left) {
+          // We cannot make the left part unitary if the left part is a zero
+          // row, so makeLeftUnitary implies no zero left rows.
+          MATHICGB_ASSERT(firstLeft != fromEnd);
+          ++firstLeft;
+        }
+        if (firstLeft.scalar() != 1) {
+          const auto modulus = static_cast<Scalar>(ring().charac());
+          const auto inverse = modularInverse(firstLeft.scalar(), modulus);
+          for (auto it = fromIt; it != fromEnd; ++it)
+            it.setScalar(modularProduct(it.scalar(), inverse, modulus));
+          MATHICGB_ASSERT(firstLeft.scalar() == 1);
+        }
+      }
+      for (; fromIt != fromEnd; ++fromIt) {
+        MATHICGB_ASSERT(fromIt.index() < mTranslate.size());
+        const auto translated = mTranslate[fromIt.index()];
+        if (translated.left)
+          left.appendEntry(translated.index, fromIt.scalar());
+        else
+          right.appendEntry(translated.index, fromIt.scalar());
+      }
+      left.rowDone();
+      right.rowDone();
+      MATHICGB_ASSERT(left.rowCount() == right.rowCount());
+      MATHICGB_ASSERT(!makeLeftUnitary || !left.emptyRow(left.rowCount() - 1));
+      MATHICGB_ASSERT
+        (!makeLeftUnitary || left.rowBegin(left.rowCount() - 1).scalar() == 1);
+    }
+  };
+  splitLeftRight
+    (matrix, reducerRows, true, quadMatrix.topLeft, quadMatrix.topRight);
+  splitLeftRight(
+    matrix,
+    reduceeRows,
+    false,
+    quadMatrix.bottomLeft,
+    quadMatrix.bottomRight
+  );
+
+#ifdef MATHICGB_DEBUG
+  for (size_t side = 0; side < 2; ++side) {
+    auto& monos = side == 0 ?
+      quadMatrix.leftColumnMonomials : quadMatrix.rightColumnMonomials;
+    for (auto it = monos.begin(); it != monos.end(); ++it) {
+      MATHICGB_ASSERT(!it->isNull());
+    }
+  }
+  for (size_t row = 0; row < quadMatrix.topLeft.rowCount(); ++row) {
+    MATHICGB_ASSERT(quadMatrix.topLeft.leadCol(row) == row);
+  }
+#endif
+
+  quadMatrix.sortColumnsLeftRightParallel();
+#ifdef MATHICGB_DEBUG
+  MATHICGB_ASSERT(quadMatrix.debugAssertValid());
+#endif
+
+  mMap.clearNonConcurrent();
+}
+
+std::pair<F4MatrixBuilder2::ColIndex, ConstMonomial>
+F4MatrixBuilder2::createColumn(
+  const const_monomial monoA,
+  const const_monomial monoB,
+  TaskFeeder& feeder
+) {
+  MATHICGB_ASSERT(!monoA.isNull());
+  MATHICGB_ASSERT(!monoB.isNull());
+
+  tbb::mutex::scoped_lock lock(mCreateColumnLock);
+  // see if the column exists now after we have synchronized
+  {
+    const auto found(ColReader(mMap).findProduct(monoA, monoB));
+    if (found.first != 0)
+      return std::make_pair(*found.first, found.second);
+  }
+
+  // The column really does not exist, so we need to create it
+  ring().monomialMult(monoA, monoB, mTmp);
+  if (!ring().monomialHasAmpleCapacity(mTmp))
+    mathic::reportError("Monomial exponent overflow in F4MatrixBuilder2.");
+  MATHICGB_ASSERT(ring().hashValid(mTmp));
+
+  // look for a reducer of mTmp
+  const size_t reducerIndex = mBasis.divisor(mTmp);
+  const bool insertLeft = (reducerIndex != static_cast<size_t>(-1));
+
+  MATHICGB_ASSERT(mLeftColCount + mRightColCount == mTranslate.size());
+
+  // Create the new left or right column
+  auto& colCount = insertLeft ? mLeftColCount : mRightColCount;
+  if (colCount == std::numeric_limits<ColIndex>::max())
+    throw std::overflow_error("Too many columns in QuadMatrix");
+  const auto newIndex = static_cast<ColIndex>(mTranslate.size());
+  const auto inserted = mMap.insert(std::make_pair(mTmp, newIndex));
+  Translated translated = {colCount, insertLeft};
+  mTranslate.push_back(translated);
+  ++colCount;
+
+  MATHICGB_ASSERT(mLeftColCount + mRightColCount == mTranslate.size());
+
+  // schedule new task if we found a reducer
+  if (insertLeft) {
+    RowTask task = {};
+    task.addToTop = true;
+    task.poly = &mBasis.poly(reducerIndex);
+    task.desiredLead = inserted.first.second.castAwayConst();
+    feeder.add(task);
+  }
+
+  return std::make_pair(*inserted.first.first, inserted.first.second);
+}
+
+void F4MatrixBuilder2::appendRowBottom(
+  const_monomial multiple,
+  const bool negate,
+  const Poly::const_iterator begin,
+  const Poly::const_iterator end,
+  SparseMatrix& matrix,
+  TaskFeeder& feeder
+) {
+  // todo: eliminate the code-duplication between here and appendRowTop.
+  MATHICGB_ASSERT(!multiple.isNull());
+  MATHICGB_ASSERT(&matrix != 0);
+
+  auto it = begin;
+updateReader:
+  // Use an on-stack const reader to make it as obvious as possible to the
+  // optimizer's alias analysis that the pointer inside the reader never
+  // changes inside the loop.
+  const ColReader reader(mMap);
+  for (; it != end; ++it) {
+    const auto col = reader.findProduct(it.getMonomial(), multiple);
+    if (col.first == 0) {
+      createColumn(it.getMonomial(), multiple, feeder);
+      goto updateReader;
+    }
+
+    const auto origScalar = it.getCoefficient();
+    MATHICGB_ASSERT(origScalar != 0);
+    const auto maybeNegated =
+      negate ? ring().coefficientNegateNonZero(origScalar) : origScalar;
+	MATHICGB_ASSERT(maybeNegated < std::numeric_limits<Scalar>::max());
+    matrix.appendEntry(*col.first, static_cast<Scalar>(maybeNegated));
+  }
+  matrix.rowDone();
+}
+
+void F4MatrixBuilder2::appendRowTop(
+  const const_monomial multiple,
+  const Poly& poly,
+  SparseMatrix& matrix,
+  TaskFeeder& feeder
+) {
+  MATHICGB_ASSERT(!multiple.isNull());
+  MATHICGB_ASSERT(&poly != 0);
+  MATHICGB_ASSERT(&matrix != 0);
+
+  auto it = poly.begin();
+  const auto end = poly.end();
+  if ((std::distance(it, end) % 2) == 1) {
+    ColReader reader(mMap);
+    const auto col = findOrCreateColumn
+      (it.getMonomial(), multiple, reader, feeder);
+	MATHICGB_ASSERT(it.getCoefficient() < std::numeric_limits<Scalar>::max());
+    MATHICGB_ASSERT(it.getCoefficient());
+    matrix.appendEntry(col.first, static_cast<Scalar>(it.getCoefficient()));
+    ++it;
+  }
+updateReader:
+  ColReader colMap(mMap);
+  MATHICGB_ASSERT((std::distance(it, end) % 2) == 0);
+  while (it != end) {
+	MATHICGB_ASSERT(it.getCoefficient() < std::numeric_limits<Scalar>::max());
+    MATHICGB_ASSERT(it.getCoefficient() != 0);
+    const auto scalar1 = static_cast<Scalar>(it.getCoefficient());
+    const const_monomial mono1 = it.getMonomial();
+
+    auto it2 = it;
+    ++it2;
+	MATHICGB_ASSERT(it2.getCoefficient() < std::numeric_limits<Scalar>::max());
+    MATHICGB_ASSERT(it2.getCoefficient() != 0);
+    const auto scalar2 = static_cast<Scalar>(it2.getCoefficient());
+    const const_monomial mono2 = it2.getMonomial();
+
+    const auto colPair = colMap.findTwoProducts(mono1, mono2, multiple);
+    if (colPair.first == 0 || colPair.second == 0) {
+      createTwoColumns(mono1, mono2, multiple, feeder);
+      goto updateReader;
+    }
+
+    matrix.appendEntry(*colPair.first, scalar1);
+    matrix.appendEntry(*colPair.second, scalar2);
+    it = ++it2;
+  }
+  matrix.rowDone();
+}
+
+void F4MatrixBuilder2::appendRowBottom(
+  const Poly* poly,
+  monomial multiply,
+  const Poly* sPairPoly,
+  monomial sPairMultiply,
+  SparseMatrix& matrix,
+  TaskFeeder& feeder
+) {
+  MATHICGB_ASSERT(!poly->isZero());
+  MATHICGB_ASSERT(!multiply.isNull());
+  MATHICGB_ASSERT(ring().hashValid(multiply));
+  MATHICGB_ASSERT(sPairPoly != 0);
+  Poly::const_iterator itA = poly->begin();
+  const Poly::const_iterator endA = poly->end();
+
+  MATHICGB_ASSERT(!sPairPoly->isZero());
+  MATHICGB_ASSERT(!sPairMultiply.isNull());
+  MATHICGB_ASSERT(ring().hashValid(sPairMultiply));
+  Poly::const_iterator itB = sPairPoly->begin();
+  Poly::const_iterator endB = sPairPoly->end();
+
+  // skip leading terms since they cancel
+  MATHICGB_ASSERT(itA.getCoefficient() == itB.getCoefficient());
+  ++itA;
+  ++itB;
+
+  const ColReader colMap(mMap);
+
+  const const_monomial mulA = multiply;
+  const const_monomial mulB = sPairMultiply;
+  bool zero = true;
+  while (true) {
+    // Watch out: we are depending on appendRowBottom to finish the row, so
+    // if you decide not to call that function in case
+    // (itA == itA && itB == endB) then you need to do that yourself.
+    if (itB == endB) {
+      if (!zero || itA != endA)
+        appendRowBottom(mulA, false, itA, endA, matrix, feeder);
+      break;
+    }
+    if (itA == endA) {
+      appendRowBottom(mulB, true, itB, endB, matrix, feeder);
+      break;
+    }
+
+    coefficient coeff = 0;
+    ColIndex col;
+    const auto colA = findOrCreateColumn
+      (itA.getMonomial(), mulA, colMap, feeder);
+    const auto colB = findOrCreateColumn
+      (itB.getMonomial(), mulB, colMap, feeder);
+    const auto cmp = ring().monomialCompare(colA.second, colB.second);
+    //const auto cmp = ring().monomialCompare
+    //  (matrix.monomialOfCol(colA), matrix.monomialOfCol(colB));
+    if (cmp != LT) {
+      coeff = itA.getCoefficient();
+      col = colA.first;
+      ++itA;
+    }
+    if (cmp != GT) {
+      coeff = ring().coefficientSubtract(coeff, itB.getCoefficient());
+      col = colB.first;
+      ++itB;
+    }
+    MATHICGB_ASSERT(coeff < std::numeric_limits<Scalar>::max());
+    if (coeff != 0) {
+      zero = false;
+      matrix.appendEntry(col, static_cast<Scalar>(coeff));
+    }
+  }
+  MATHICGB_ASSERT
+    (matrix.rowCount() == 0 || !matrix.emptyRow(matrix.rowCount() - 1));
+}
diff --git a/src/mathicgb/F4MatrixBuilder2.hpp b/src/mathicgb/F4MatrixBuilder2.hpp
new file mode 100755
index 0000000..d3ce5d9
--- /dev/null
+++ b/src/mathicgb/F4MatrixBuilder2.hpp
@@ -0,0 +1,156 @@
+#ifndef F4_MATRIX_BUILDER_2_GUARD
+#define F4_MATRIX_BUILDER_2_GUARD
+
+#include "SparseMatrix.hpp"
+#include "Poly.hpp"
+#include "PolyRing.hpp"
+#include "PolyBasis.hpp"
+#include "QuadMatrix.hpp"
+#include "MonomialMap.hpp"
+#include <tbb/mutex.h>
+#include <vector>
+
+/** Class for constructing an F4 matrix.
+
+  @todo: this class does not offer exception guarantees. It's just not
+  very workable without an RAII monomial handle or a scope exit functionality,
+  so add one of those before fixing this. */
+class F4MatrixBuilder2 {
+private:
+  typedef SparseMatrix::ColIndex ColIndex;
+  typedef SparseMatrix::Scalar Scalar;
+  typedef MonomialMap<ColIndex> Map;
+  typedef SparseMatrix::RowIndex RowIndex;
+
+public:
+  /// memoryQuantum is how much to increase the memory size by each time the
+  /// current amount of memory is exhausted. A value of 0 indicates to start
+  /// small and double the quantum at each exhaustion.
+  F4MatrixBuilder2(const PolyBasis& basis, size_t memoryQuantum = 0);
+
+  /** Schedules a row representing the S-polynomial between polyA and
+    polyB to be added to the matrix. No ownership is taken, but polyA
+    and polyB must remain valid until the matrix is constructed.
+
+    Currently, the two monomials must be monic, though this is just
+    because they always happen to be monic so there was no reason to
+    support the non-monic case. */
+  void addSPolynomialToMatrix(const Poly& polyA, const Poly& polyB);
+
+  /** Schedules a row representing multiple*poly to be added to the
+    matrix. No ownership is taken, but poly must remain valid until
+    the matrix is constructed. multiple is copied so it need not
+    remain valid. */
+  void addPolynomialToMatrix(const_monomial multiple, const Poly& poly);
+
+  /// as the overload with a multiple, just letting multiple be the
+  /// identity.
+  void addPolynomialToMatrix(const Poly& poly);
+
+  /** Builds an F4 matrix to the specifications given. Also clears the
+    information in this object.
+
+    The right columns are ordered by decreasing monomial of each
+    column according to the order from the basis. The left columns are
+    ordered in some way so that the first entry in each top row (the
+    pivot) has a lower index than any other entries in that row.
+
+    The matrix contains a reducer/pivot for every monomial that can be
+    reduced by the basis and that is present in the matrix. There is
+    no guarantee that the bottom part of the matrix contains rows that
+    exactly correspond to the polynomials that have been scheduled to
+    be added to the matrix. It is only guaranteed that the whole matrix has
+    the same row-space as though that had been the case. */
+  void buildMatrixAndClear(QuadMatrix& matrix);
+
+  const PolyRing& ring() const {return mBasis.ring();}
+
+private:
+  typedef const Map::Reader ColReader;
+  typedef std::vector<monomial> Monomials;
+
+  /// Represents the task of adding a row to the matrix. If sPairPoly is null
+  /// then the row to add is multiply * poly. Otherwise, the row to add is
+  ///   multiply * poly - sPairMultiply * sPairPoly
+  /// where sPairMultiply makes the lead terms cancel.
+  struct RowTask {
+    bool addToTop; // add the row to the bottom if false
+    monomial desiredLead; // multiply monomial onto poly to get this lead
+    const Poly* poly;
+    const Poly* sPairPoly;
+    monomial sPairMultiply;
+  };
+  typedef tbb::parallel_do_feeder<RowTask> TaskFeeder;
+
+  /// Creates a column with monomial label x and schedules a new row to
+  /// reduce that column if possible. Here x is monoA if monoB is
+  /// null and otherwise x is the product of monoA and monoB.
+  MATHICGB_NO_INLINE
+  std::pair<ColIndex, ConstMonomial> createColumn(
+    const_monomial monoA,
+    const_monomial monoB,
+    TaskFeeder& feeder
+  );
+
+  void appendRowTop(
+    const_monomial multiple,
+    const Poly& poly,
+    SparseMatrix& matrix,
+    TaskFeeder& feeder
+  );
+  void appendRowBottom(
+    const Poly* poly,
+    monomial multiply,
+    const Poly* sPairPoly,
+    monomial sPairMultiply,
+    SparseMatrix& matrix,
+    TaskFeeder& feeder
+  );
+  void appendRowBottom(
+    const_monomial multiple,
+    bool negate,
+    Poly::const_iterator begin,
+    Poly::const_iterator end,
+    SparseMatrix& matrix,
+    TaskFeeder& feeder
+  );
+
+  MATHICGB_NO_INLINE
+  std::pair<ColIndex, ConstMonomial> findOrCreateColumn(
+    const_monomial monoA,
+    const_monomial monoB,
+    TaskFeeder& feeder
+  );
+  
+  MATHICGB_INLINE
+  std::pair<ColIndex, ConstMonomial> findOrCreateColumn(
+    const_monomial monoA,
+    const_monomial monoB,
+    const ColReader& colMap,
+    TaskFeeder& feeder
+  );
+
+  MATHICGB_NO_INLINE
+  void createTwoColumns(
+    const const_monomial monoA1,
+    const const_monomial monoA2,
+    const const_monomial monoB,
+    TaskFeeder& feeder
+  );
+
+  struct Translated {
+    ColIndex index;
+    bool left;
+  };
+  std::vector<const Translated> mTranslate;
+  ColIndex mLeftColCount;
+  ColIndex mRightColCount;
+  const size_t mMemoryQuantum;
+  tbb::mutex mCreateColumnLock;
+  monomial mTmp;
+  const PolyBasis& mBasis;
+  Map mMap;
+  std::vector<RowTask> mTodo;
+};
+
+#endif
diff --git a/src/mathicgb/F4Reducer.cpp b/src/mathicgb/F4Reducer.cpp
index 52b7e09..20f3ccd 100755
--- a/src/mathicgb/F4Reducer.cpp
+++ b/src/mathicgb/F4Reducer.cpp
@@ -2,12 +2,14 @@
 #include "F4Reducer.hpp"
 
 #include "F4MatrixBuilder.hpp"
+#include "F4MatrixBuilder2.hpp"
 #include "F4MatrixReducer.hpp"
 #include "QuadMatrix.hpp"
 #include <iostream>
 #include <limits>
 
-F4Reducer::F4Reducer(const PolyRing& ring):
+F4Reducer::F4Reducer(const PolyRing& ring, Type type):
+  mType(type),
   mFallback(Reducer::makeReducer(Reducer::Reducer_BjarkeGeo, ring)),
   mRing(ring),
   mMemoryQuantum(0),
@@ -82,15 +84,21 @@ void F4Reducer::classicReduceSPolySet(
   {
     QuadMatrix qm;
     {
-      F4MatrixBuilder builder(basis, mMemoryQuantum);
-      for (auto it = spairs.begin(); it != spairs.end(); ++it) {
-        builder.addSPolynomialToMatrix
-          (basis.poly(it->first), basis.poly(it->second));
+      if (mType == OldType) {
+        F4MatrixBuilder builder(basis, mMemoryQuantum);
+        for (auto it = spairs.begin(); it != spairs.end(); ++it) {
+          builder.addSPolynomialToMatrix
+            (basis.poly(it->first), basis.poly(it->second));
+        }
+        builder.buildMatrixAndClear(qm);
+      } else {
+        F4MatrixBuilder2 builder(basis, mMemoryQuantum);
+        for (auto it = spairs.begin(); it != spairs.end(); ++it) {
+          builder.addSPolynomialToMatrix
+            (basis.poly(it->first), basis.poly(it->second));
+        }
+        builder.buildMatrixAndClear(qm);
       }
-      builder.buildMatrixAndClear(qm);
-
-      // there has to be something to reduce
-      MATHICGB_ASSERT(qm.bottomLeft.rowCount() > 0);
     }
     saveMatrix(qm);
     reduced = F4MatrixReducer(basis.ring().charac()).
@@ -139,13 +147,17 @@ void F4Reducer::classicReducePolySet
   {
     QuadMatrix qm;
     {
-      F4MatrixBuilder builder(basis, mMemoryQuantum);
-      for (auto it = polys.begin(); it != polys.end(); ++it)
-        builder.addPolynomialToMatrix(**it);
-      builder.buildMatrixAndClear(qm);
-
-      // there has to be something to reduce
-      MATHICGB_ASSERT(qm.bottomLeft.rowCount() > 0);
+      if (mType == OldType) {
+        F4MatrixBuilder builder(basis, mMemoryQuantum);
+        for (auto it = polys.begin(); it != polys.end(); ++it)
+          builder.addPolynomialToMatrix(**it);
+        builder.buildMatrixAndClear(qm);
+      } else {
+        F4MatrixBuilder2 builder(basis, mMemoryQuantum);
+        for (auto it = polys.begin(); it != polys.end(); ++it)
+          builder.addPolynomialToMatrix(**it);
+        builder.buildMatrixAndClear(qm);
+      }
     }
     saveMatrix(qm);
     reduced = F4MatrixReducer(basis.ring().charac()).
diff --git a/src/mathicgb/F4Reducer.hpp b/src/mathicgb/F4Reducer.hpp
index c86676b..1d23de7 100755
--- a/src/mathicgb/F4Reducer.hpp
+++ b/src/mathicgb/F4Reducer.hpp
@@ -8,7 +8,12 @@ class QuadMatrix;
 
 class F4Reducer : public Reducer {
 public:
-  F4Reducer(const PolyRing& ring);
+  enum Type {
+    OldType,
+    NewType
+  };
+
+  F4Reducer(const PolyRing& ring, Type type);
 
   /// Store all future matrices to file-1.mat, file-2.mat and so on.
   /// Matrices with less than minEntries non-zero entries are not stored.
@@ -52,6 +57,7 @@ public:
 private:
   void saveMatrix(const QuadMatrix& matrix);
 
+  Type mType;
   std::unique_ptr<Reducer> mFallback;
   const PolyRing& mRing;
   size_t mMemoryQuantum;
diff --git a/src/mathicgb/MonomialMap.hpp b/src/mathicgb/MonomialMap.hpp
index 7da2d23..bcaa043 100755
--- a/src/mathicgb/MonomialMap.hpp
+++ b/src/mathicgb/MonomialMap.hpp
@@ -197,7 +197,7 @@ private:
 
   Atomic<FixedSizeMap*> mMap;
   const PolyRing& mRing;
-  tbb::mutex mInsertionMutex;
+  mutable tbb::mutex mInsertionMutex;
 
   /// Only access this field while holding the mInsertionMutex lock.
   size_t mCapacityUntilGrowth;
diff --git a/src/mathicgb/QuadMatrix.cpp b/src/mathicgb/QuadMatrix.cpp
index 041e425..29ce67a 100755
--- a/src/mathicgb/QuadMatrix.cpp
+++ b/src/mathicgb/QuadMatrix.cpp
@@ -10,6 +10,10 @@ bool QuadMatrix::debugAssertValid() const {
 #ifndef MATHICGB_DEBUG
   return true;
 #else
+  MATHICGB_ASSERT(topLeft.debugAssertValid());
+  MATHICGB_ASSERT(bottomLeft.debugAssertValid());
+  MATHICGB_ASSERT(topRight.debugAssertValid());
+  MATHICGB_ASSERT(bottomRight.debugAssertValid());
   if (!leftColumnMonomials.empty() || !rightColumnMonomials.empty()) {
     MATHICGB_ASSERT(topLeft.computeColCount() <= leftColumnMonomials.size());
     MATHICGB_ASSERT(bottomLeft.computeColCount() <=
diff --git a/src/mathicgb/Reducer.cpp b/src/mathicgb/Reducer.cpp
index b465f79..47364be 100755
--- a/src/mathicgb/Reducer.cpp
+++ b/src/mathicgb/Reducer.cpp
@@ -102,8 +102,10 @@ std::unique_ptr<Reducer> Reducer::makeReducerNullOnUnknown(
   case Reducer_Geobucket_Hashed_Packed:
     return std::unique_ptr<Reducer>(new ReducerHashPack<mic::Geobucket>(ring));
 
-  case Reducer_F4:
-      return make_unique<F4Reducer>(ring);
+  case Reducer_F4_Old:
+    return make_unique<F4Reducer>(ring, F4Reducer::OldType);
+  case Reducer_F4_New:
+    return make_unique<F4Reducer>(ring, F4Reducer::NewType);
 
   default:
     break;
@@ -143,7 +145,8 @@ Reducer::ReducerType Reducer::reducerType(int typ)
   case 23: return Reducer_Geobucket_Dedup_Packed;
   case 24: return Reducer_Geobucket_Hashed_Packed;
 
-  case 25: return Reducer_F4;
+  case 25: return Reducer_F4_Old;
+  case 26: return Reducer_F4_New;
 
   default: return Reducer_PolyHeap;
   }
@@ -181,7 +184,8 @@ void Reducer::displayReducerTypes(std::ostream &o)
   o << "  23   Geobucket.Dedup.Packed" << std::endl;
   o << "  24   Geobucket.Hashed.Packed" << std::endl;
 
-  o << "  25   F4 reducer" << std::endl;
+  o << "  25   F4 reducer, old" << std::endl;
+  o << "  26   F4 reducer, new" << std::endl;
 }
 
 // Todo: can't this be machine generated?
diff --git a/src/mathicgb/Reducer.hpp b/src/mathicgb/Reducer.hpp
index 2de1983..23f351b 100755
--- a/src/mathicgb/Reducer.hpp
+++ b/src/mathicgb/Reducer.hpp
@@ -98,7 +98,8 @@ public:
     Reducer_Geobucket_Dedup_Packed,
     Reducer_Geobucket_Hashed_Packed,
 
-    Reducer_F4
+    Reducer_F4_Old,
+    Reducer_F4_New
   };
 
   static std::unique_ptr<Reducer> makeReducer
diff --git a/src/mathicgb/SparseMatrix.hpp b/src/mathicgb/SparseMatrix.hpp
index 77270c6..a6626e3 100755
--- a/src/mathicgb/SparseMatrix.hpp
+++ b/src/mathicgb/SparseMatrix.hpp
@@ -46,6 +46,7 @@ public:
   typedef uint32 ColIndex;
   typedef uint16 Scalar;
   class ConstRowIterator;
+  class RowIterator;
 
   /// Construct a matrix with no rows.
   SparseMatrix(const size_t memoryQuantum = 0):
@@ -123,12 +124,24 @@ public:
     return ConstRowIterator(r.mIndicesBegin, r.mScalarsBegin);
   }
 
+  RowIterator rowBegin(RowIndex row) {
+    MATHICGB_ASSERT(row < rowCount());
+    const Row& r = mRows[row];
+    return RowIterator(r.mIndicesBegin, r.mScalarsBegin);
+  }
+
   ConstRowIterator rowEnd(RowIndex row) const {
     MATHICGB_ASSERT(row < rowCount());
     const Row& r = mRows[row];
     return ConstRowIterator(r.mIndicesEnd, r.mScalarsEnd);
   }
 
+  RowIterator rowEnd(RowIndex row) {
+    MATHICGB_ASSERT(row < rowCount());
+    const Row& r = mRows[row];
+    return RowIterator(r.mIndicesEnd, r.mScalarsEnd);
+  }
+
   /// Returns the index of the first entry in the given row. This is
   /// the first entry that you added to the row - so not necessarily the
   /// minimum column index in that row. The row in question must have at
@@ -288,6 +301,58 @@ public:
     const Scalar* mScalarIt;
   };
 
+  /// Iterates through the entries in a row.
+  class RowIterator {
+  public:
+    typedef const std::pair<ColIndex, Scalar> value_type;
+	typedef ptrdiff_t difference_type;
+    typedef size_t distance_type;
+    typedef value_type* pointer;
+    typedef value_type& reference;
+    typedef std::random_access_iterator_tag iterator_category;
+
+    RowIterator& operator++() {
+      ++mScalarIt;
+      ++mColIndexIt;
+      return *this;
+    }
+
+    value_type operator*() const {return value_type(index(), scalar());}
+
+    bool operator<(const RowIterator& it) const {
+      return mColIndexIt < it.mColIndexIt;
+    }
+
+    difference_type operator-(const RowIterator& it) const {
+      return mColIndexIt - it.mColIndexIt;
+    }
+
+    bool operator==(const RowIterator& it) const {
+      return mColIndexIt == it.mColIndexIt;
+    }
+
+    bool operator!=(const RowIterator& it) const {return !(*this == it);}
+    const Scalar& scalar() const {return *mScalarIt;}
+    const ColIndex& index() const {return *mColIndexIt;}
+
+    void setScalar(const Scalar scalar) {*mScalarIt = scalar;}
+    void setIndex(const ColIndex index) {*mColIndexIt = index;}
+
+  private:
+    friend class SparseMatrix;
+    RowIterator(
+      ColIndex* const indicesIt,
+      Scalar* const scalarIt
+    ):
+      mColIndexIt(indicesIt),
+      mScalarIt(scalarIt)
+    {
+    }
+
+    ColIndex* mColIndexIt;
+    Scalar* mScalarIt;
+  };
+
   bool debugAssertValid() const;
 
 private:
diff --git a/src/test/F4MatrixBuilder.cpp b/src/test/F4MatrixBuilder.cpp
index c96d6fc..4b4d27f 100755
--- a/src/test/F4MatrixBuilder.cpp
+++ b/src/test/F4MatrixBuilder.cpp
@@ -80,13 +80,21 @@ TEST(F4MatrixBuilder, SPair) {
     builder.addSPolynomialToMatrix(p1, p2);
     QuadMatrix qm;
     builder.buildMatrixAndClear(qm);
-    const char* str = 
+    const char* const str1 = 
       "Left columns: c2d\n"
       "Right columns: bd 1\n"
       "0: 0#1   | 0: 1#3  \n"
       "         |         \n"
       "0: 0#100 | 0: 0#100\n";
-    ASSERT_EQ(str, qm.toString());
+    const char* const str2 = 
+      "Left columns: c2d\n"
+      "Right columns: bd 1\n"
+      "0: 0#1 | 0: 0#1\n"
+      "       |       \n"
+      "0: 0#1 | 0: 1#3\n";
+    std::string qmStr = qm.toString();
+    ASSERT_TRUE(str1 == qmStr || str2 == qmStr) <<
+      "\n** str1: " << str1 << "\n** qm: " << qmStr;
   }
 }
 
diff --git a/src/test/gb-test.cpp b/src/test/gb-test.cpp
index 85127ce..a4ba21d 100755
--- a/src/test/gb-test.cpp
+++ b/src/test/gb-test.cpp
@@ -49,139 +49,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	sPairGroupSize	threadCount
-2	12	1	0	0	0	0	0	0	0	0	1	1
-3	4	2	1	0	1	1	0	0	1	1	100	8
-0	11	2	2	1	0	0	1	1	0	0	100	2
-1	24	1	2	0	1	0	0	0	1	1	2	2
-0	8	2	0	0	0	1	0	0	1	1	100	1
-1	6	1	1	1	0	0	1	1	0	0	10	8
-3	15	1	0	1	0	0	1	1	1	0	100	1
-2	0	2	1	0	1	1	0	0	0	1	1	2
-2	6	2	2	0	1	1	0	0	1	1	0	1
-2	0	1	0	1	0	0	1	0	1	0	10	1
-0	3	2	2	1	0	0	0	1	1	0	1	8
-1	23	2	0	1	0	0	1	1	0	0	100	2
-3	5	1	2	0	1	1	0	0	0	1	10	2
-1	15	2	0	0	1	1	0	0	0	1	1	8
-0	5	2	1	1	0	0	1	1	1	0	1	1
-2	13	1	1	1	0	0	1	1	1	0	1	8
-1	10	2	1	1	0	0	1	1	0	0	2	1
-2	17	1	0	1	0	0	0	1	1	0	100	1
-0	6	1	0	1	0	0	0	1	1	0	100	2
-0	15	2	2	1	0	0	0	1	0	0	10	2
-2	9	1	1	1	0	0	0	1	1	0	100	2
-0	0	1	0	1	0	0	1	1	0	0	0	8
-1	5	2	1	1	0	0	1	1	0	0	0	8
-3	7	2	2	1	0	0	1	1	0	0	0	2
-3	25	1	0	1	0	0	0	0	0	0	1	8
-2	5	1	0	1	0	0	1	1	0	0	100	2
-0	19	2	1	0	1	1	0	0	0	0	0	2
-0	25	2	1	1	0	0	1	1	1	0	10	1
-3	6	1	0	0	1	0	0	0	0	1	1	2
-2	3	1	0	0	1	1	0	0	0	1	2	8
-0	9	2	0	0	1	1	0	0	0	1	2	8
-3	5	2	2	0	0	0	0	0	0	1	2	2
-3	0	2	2	0	0	1	0	0	1	0	100	1
-2	18	2	1	0	0	1	0	0	0	0	1	1
-0	21	1	1	1	0	0	1	1	1	0	100	8
-1	4	1	2	1	0	0	1	1	0	0	10	1
-0	22	1	1	1	0	0	1	0	0	0	1	8
-2	11	1	1	0	1	1	0	0	1	1	2	8
-3	11	2	0	0	0	0	0	0	1	1	1	1
-1	19	1	2	0	0	0	0	0	1	1	1	1
-1	9	1	2	1	0	0	1	0	1	0	10	1
-0	13	2	0	0	1	1	0	0	0	1	0	1
-2	20	1	1	1	0	0	1	1	1	0	100	8
-2	1	1	0	0	1	1	0	0	1	0	10	2
-1	18	1	2	0	1	0	0	0	1	1	2	8
-3	19	1	0	1	0	0	1	1	0	0	100	8
-1	13	2	2	0	1	1	0	0	1	1	100	2
-2	8	1	1	1	0	0	1	1	0	0	10	2
-3	23	1	1	0	1	1	0	0	1	1	0	1
-2	7	1	1	0	1	1	0	0	1	1	2	8
-3	17	2	1	0	1	1	0	0	0	1	2	2
-0	23	2	2	1	0	0	0	1	1	0	2	8
-3	20	2	2	0	1	1	0	0	0	1	1	1
-1	3	2	1	0	0	1	0	0	0	1	100	2
-3	22	2	2	0	1	1	0	0	1	1	0	2
-0	4	1	0	1	0	0	1	1	0	0	2	2
-3	12	2	1	0	1	1	0	0	1	1	100	8
-2	15	2	1	1	0	0	0	1	1	0	0	1
-2	14	1	0	0	1	0	0	0	0	1	10	2
-2	4	1	2	0	1	1	0	0	1	0	1	2
-0	14	2	2	1	0	0	1	1	1	0	0	1
-3	13	1	0	1	0	0	1	0	1	0	10	1
-1	12	2	2	1	0	0	1	1	1	0	2	2
-2	19	2	2	0	0	0	0	0	1	1	2	1
-1	0	2	1	0	1	0	0	0	1	0	2	8
-3	8	2	2	1	0	0	0	1	1	0	0	8
-1	15	1	2	1	0	0	1	1	0	0	2	2
-2	23	1	0	0	1	0	0	0	0	1	10	8
-3	18	2	0	1	0	0	1	1	1	0	10	2
-3	10	1	2	0	1	1	0	0	1	1	100	8
-1	22	2	0	1	0	0	1	1	1	0	2	1
-1	16	2	1	0	0	0	0	0	0	1	0	8
-3	21	2	0	0	1	1	0	0	0	1	2	2
-1	11	2	2	0	1	1	0	0	0	1	0	1
-3	9	2	1	1	0	0	0	1	1	0	0	1
-2	16	1	2	1	0	0	1	1	1	0	100	1
-0	18	2	2	0	0	0	0	0	1	0	100	2
-1	1	2	1	0	0	0	0	0	0	1	2	1
-0	17	2	2	0	0	0	0	0	0	1	1	8
-3	16	2	0	1	0	0	1	0	0	0	1	2
-1	11	2	2	1	0	0	1	0	1	0	10	2
-0	1	2	2	0	1	0	0	0	0	1	0	8
-1	21	1	2	1	0	0	1	1	1	0	10	1
-2	22	2	2	1	0	0	1	0	1	0	10	1
-1	25	2	2	1	0	0	0	1	1	0	100	2
-1	14	1	1	0	0	1	0	0	1	1	100	8
-1	22	2	0	1	0	0	1	1	1	0	100	8
-3	23	2	2	1	0	0	0	1	1	0	1	2
-0	10	1	0	0	0	0	0	0	0	1	10	2
-3	24	2	0	1	0	0	1	1	0	0	100	1
-3	3	2	2	0	0	1	0	0	0	1	10	1
-2	2	2	1	0	1	1	0	0	0	1	1	1
-2	25	1	1	1	0	0	1	0	1	0	0	1
-2	24	2	1	0	0	1	0	0	0	0	0	8
-1	7	2	0	0	1	0	0	0	0	1	10	1
-0	12	2	1	1	0	0	1	0	0	0	0	8
-0	25	1	1	1	0	0	0	1	1	0	2	2
-1	20	1	0	1	0	0	0	1	0	0	2	2
-0	19	2	0	1	0	0	1	0	0	0	10	8
-0	6	1	0	0	1	1	0	0	1	0	2	1
-1	2	1	2	1	0	0	1	1	1	0	10	2
-2	21	2	1	1	0	0	1	1	1	0	0	8
-0	24	2	0	1	0	0	1	1	1	0	1	1
-1	17	2	2	1	0	0	1	1	1	0	10	2
-0	7	2	0	1	0	0	1	0	0	0	1	8
-1	8	2	0	0	1	1	0	0	1	1	2	2
-0	20	2	0	0	0	0	0	0	1	1	10	1
-3	1	1	0	0	0	1	0	0	0	1	100	1
-3	18	2	2	1	0	0	1	1	0	0	0	1
-3	14	2	0	0	0	0	0	0	1	1	1	8
-2	10	2	2	1	0	0	1	0	1	0	1	8
-2	17	2	0	1	0	0	1	1	0	0	0	8
-0	12	1	0	0	1	0	0	0	0	1	10	1
-2	9	2	2	0	1	0	0	0	0	1	1	2
-3	10	1	0	0	0	1	0	0	1	0	0	1
-0	2	2	0	0	1	0	0	0	1	1	2	8
-3	2	2	0	0	0	0	0	0	1	1	0	2
-2	4	2	0	0	0	0	0	0	0	0	0	2
-0	16	1	1	1	0	0	1	1	0	0	10	2
-3	13	2	2	0	1	0	0	0	1	1	2	8
-3	7	2	0	1	0	0	1	1	1	0	100	1
-3	8	2	1	0	1	0	0	0	1	1	1	8
-2	1	2	0	0	1	0	0	0	0	1	1	8
-3	20	1	1	0	1	0	0	0	0	0	0	2
-2	14	1	1	0	1	0	0	0	1	1	2	8
-2	2	1	2	1	0	0	1	0	0	0	100	1
-2	21	2	1	1	0	0	1	0	1	0	1	2
-3	24	2	2	0	1	1	0	0	1	1	10	1
-3	3	2	2	0	0	0	0	0	0	1	0	1
-2	1	1	0	1	0	0	1	1	0	0	1	8
-1	16	1	1	0	1	1	0	0	0	0	2	2
-0	3	2	0	1	0	0	1	1	0	0	0	1
+spairQueue	reducerType	divLookup	monTable	buchberger	postponeKoszul	useBaseDivisors	autoTailReduce	autoTopReduce	preferSparseReducers	useSingularCriterionEarly	sPairGroupSize	threadCount
+0	11	4	0	0	0	0	0	0	0	0	1	1
+1	13	1	1	0	1	1	0	0	1	1	0	2
+3	16	2	2	1	0	0	1	1	1	0	10	8
+2	4	3	2	0	1	1	0	0	0	1	100	8
+2	14	3	1	1	0	0	1	1	0	0	0	1
+1	2	1	0	1	0	0	1	1	1	0	100	2
+3	23	2	0	0	0	1	0	0	1	1	2	1
+0	21	4	2	1	0	0	1	1	0	0	2	2
+0	21	4	1	0	1	1	0	0	1	1	1	8
+1	26	2	2	1	0	0	0	1	0	0	1	2
+3	19	1	1	1	0	0	1	0	0	0	100	1
+2	9	3	0	0	1	1	0	0	1	0	2	8
+2	10	1	2	0	1	0	0	0	1	1	1	1
+0	2	2	2	0	1	1	0	0	0	1	0	8
+3	15	3	1	1	0	0	1	1	1	0	1	2
+3	25	4	0	1	0	0	1	0	1	0	0	8
+1	23	1	1	1	0	0	1	1	0	0	0	8
+1	15	4	2	0	1	1	0	0	0	1	0	1
+2	20	2	1	1	0	0	1	0	1	0	100	2
+0	26	3	0	1	0	0	1	0	1	0	0	1
+0	4	1	1	1	0	0	1	1	1	0	2	2
+2	22	4	1	1	0	0	0	1	0	0	1	1
+3	17	4	1	0	1	1	0	0	1	1	100	8
+1	22	3	2	0	1	1	0	0	1	1	100	8
+0	25	1	1	1	0	0	0	1	0	0	10	1
+0	23	4	2	0	1	0	0	0	1	1	100	2
+0	6	2	1	1	0	0	1	0	1	0	100	8
+3	20	1	0	0	1	1	0	0	0	1	0	1
+3	1	2	2	0	0	0	0	0	0	1	1	1
+1	20	4	0	0	1	1	0	0	0	1	10	8
+3	9	4	1	0	0	0	0	0	0	1	100	1
+0	22	1	0	1	0	0	1	1	0	0	10	2
+1	1	4	1	1	0	0	1	1	1	0	100	8
+1	15	1	0	0	0	0	0	0	1	1	2	8
+2	2	4	1	1	0	0	1	1	0	0	1	1
+2	6	4	0	0	1	1	0	0	0	1	1	1
+0	20	3	2	0	0	0	0	0	0	1	1	8
+0	8	1	1	1	0	0	1	0	0	0	100	8
+0	15	2	0	1	0	0	0	1	0	0	100	8
+2	3	3	1	0	1	0	0	0	0	1	10	2
+2	18	3	2	0	1	1	0	0	1	0	2	1
+2	1	3	0	1	0	0	0	1	0	0	2	2
+3	10	4	1	1	0	0	1	1	0	0	0	8
+3	22	2	1	1	0	0	1	1	1	0	0	8
+0	7	4	2	0	1	0	0	0	0	1	0	2
+1	20	4	2	1	0	0	1	1	0	0	2	2
+0	18	2	0	0	0	0	0	0	0	1	0	2
+0	17	3	0	1	0	0	1	1	0	0	0	2
+1	6	1	2	1	0	0	1	1	1	0	0	2
+0	13	3	0	1	0	0	1	1	0	0	1	1
+3	7	2	0	1	0	0	1	1	1	0	2	8
+1	7	3	1	0	1	1	0	0	0	1	1	1
+1	16	3	0	0	1	1	0	0	0	1	0	2
+1	18	1	1	0	1	1	0	0	0	1	10	8
+1	17	2	2	0	0	0	0	0	0	1	2	1
+1	9	1	2	0	0	0	0	0	0	1	1	2
+1	14	1	0	0	1	1	0	0	1	1	1	8
+0	10	2	0	0	0	1	0	0	0	1	2	2
+3	21	2	0	1	0	0	0	1	0	0	10	1
+1	12	2	0	1	0	0	0	1	0	0	1	1
+0	0	3	2	0	0	1	0	0	0	1	1	2
+3	3	4	0	1	0	0	1	1	1	0	2	8
+1	10	3	0	1	0	0	1	0	1	0	10	8
+2	26	1	1	1	0	0	1	1	1	0	10	8
+2	8	2	0	0	1	1	0	0	1	1	10	2
+3	6	3	0	0	0	0	0	0	1	1	10	1
+1	4	2	0	0	0	0	0	0	1	1	0	1
+3	0	1	0	1	0	0	1	1	1	0	2	8
+1	8	3	2	1	0	0	0	1	1	0	1	1
+2	12	3	2	0	1	1	0	0	1	1	10	8
+2	21	3	2	0	0	0	0	0	1	1	0	8
+0	19	2	2	0	1	1	0	0	1	1	10	2
+1	19	4	0	0	1	0	0	0	1	1	1	8
+0	16	1	1	0	0	1	0	0	1	1	2	1
+0	5	4	2	1	0	0	1	0	0	0	0	1
+3	14	2	2	0	0	0	0	0	0	1	2	2
+3	11	2	1	0	1	1	0	0	1	1	2	8
+3	8	4	2	0	1	1	0	0	1	1	2	1
+2	17	1	0	1	0	0	1	0	0	0	1	1
+0	3	1	2	1	0	0	1	1	1	0	0	1
+1	25	3	2	1	0	0	0	1	1	0	100	2
+2	13	4	2	0	1	0	0	0	0	1	2	8
+2	19	3	1	0	0	1	0	0	0	1	0	2
+1	0	4	1	1	0	0	1	0	0	0	10	1
+1	21	1	2	0	0	1	0	0	0	1	100	2
+0	1	1	1	1	0	0	1	0	0	0	0	2
+3	18	4	1	0	0	1	0	0	1	1	100	1
+0	9	2	0	0	0	0	0	0	1	1	10	8
+3	4	4	2	0	0	1	0	0	0	1	1	2
+3	13	2	1	0	1	0	0	0	1	1	100	8
+2	25	2	2	1	0	0	1	1	0	0	2	1
+3	26	4	2	1	0	0	1	1	1	0	2	8
+1	3	2	0	0	1	1	0	0	0	1	1	1
+3	24	2	1	0	1	1	0	0	0	1	10	1
+1	24	3	2	1	0	0	1	1	1	0	1	2
+3	18	4	0	0	1	0	0	0	1	1	1	1
+0	14	4	0	1	0	0	0	1	1	0	10	1
+3	12	4	1	1	0	0	1	0	1	0	2	2
+2	0	2	1	1	0	0	1	1	0	0	0	1
+0	22	4	1	1	0	0	1	1	0	0	2	1
+2	13	3	2	1	0	0	1	1	1	0	10	2
+0	12	1	1	0	0	0	0	0	0	1	0	2
+0	17	1	0	1	0	0	1	1	1	0	10	2
+1	5	2	1	0	1	1	0	0	1	1	1	8
+2	23	3	0	0	1	0	0	0	1	0	10	2
+2	25	4	2	1	0	0	1	1	0	0	1	1
+2	26	1	0	1	0	0	0	0	1	0	100	1
+1	0	1	0	1	0	0	0	1	1	0	100	8
+2	4	1	2	0	1	1	0	0	1	1	10	8
+2	11	3	2	1	0	0	1	1	1	0	10	2
+2	16	4	2	1	0	0	0	1	1	0	1	8
+3	9	2	2	0	0	1	0	0	1	1	0	1
+2	14	1	2	1	0	0	1	0	0	0	100	8
+3	1	3	2	1	0	0	1	1	1	0	10	2
+0	23	2	0	1	0	0	1	1	0	0	1	2
+0	10	4	0	1	0	0	1	1	1	0	100	1
+2	3	2	2	0	0	1	0	0	0	0	100	2
+3	2	3	2	0	0	1	0	0	1	1	10	2
+2	15	1	1	1	0	0	1	0	1	0	10	8
+1	11	1	0	0	1	0	0	0	0	1	100	2
+2	12	1	1	1	0	0	1	1	1	0	100	2
+1	2	2	2	1	0	0	1	0	1	0	2	1
+0	24	1	0	0	1	0	0	0	1	1	2	8
+2	7	1	1	1	0	0	1	0	1	0	10	1
+1	8	2	1	1	0	0	1	0	1	0	0	2
+2	6	4	1	0	0	1	0	0	1	1	2	1
+2	24	4	2	1	0	0	0	1	0	0	0	2
+2	5	1	0	1	0	0	1	1	1	0	2	2
+3	5	3	0	0	1	1	0	0	0	1	100	8
+2	16	1	0	1	0	0	1	0	1	0	100	2
+3	5	1	0	0	0	1	0	0	0	1	10	1
+3	24	1	1	1	0	0	1	0	1	0	100	2
+0	19	1	2	1	0	0	1	1	1	0	2	1
+3	18	2	1	1	0	0	1	1	0	0	100	8
+1	11	1	2	1	0	0	1	1	1	0	0	8
+2	0	3	1	0	1	1	0	0	0	1	1	2
+0	1	3	0	0	1	1	0	0	0	1	10	1
+3	7	2	0	0	0	0	0	0	1	1	100	1
+2	9	4	1	1	0	0	1	1	0	0	2	2
 );
   std::istringstream tests(allPairsTests);
   // skip the initial line with the parameter names.
@@ -222,7 +229,7 @@ spairQueue	reducerType	divLookup	monTable	buchberger	postponeKoszul	useBaseDivis
 
     int divLookup;
     tests >> divLookup;
-    MATHICGB_ASSERT(1 <= divLookup && divLookup <= 2);
+    MATHICGB_ASSERT(1 <= divLookup && divLookup <= 4);
 
     int monTable;
     tests >> monTable;
@@ -271,6 +278,7 @@ spairQueue	reducerType	divLookup	monTable	buchberger	postponeKoszul	useBaseDivis
     MATHICGB_ASSERT(buchberger || !autoTopReduce);
     MATHICGB_ASSERT(buchberger || !autoTailReduce);
     MATHICGB_ASSERT(buchberger || reducerType != 25);
+    MATHICGB_ASSERT(buchberger || reducerType != 26);
     MATHICGB_ASSERT(!buchberger || !postponeKoszul);
     MATHICGB_ASSERT(!buchberger || !useBaseDivisors);
     MATHICGB_ASSERT(!buchberger || !useSingularCriterionEarly);
diff --git a/src/test/pict.in b/src/test/pict.in
index 0eb81ff..5b29f99 100755
--- a/src/test/pict.in
+++ b/src/test/pict.in
@@ -23,8 +23,8 @@
 # This is the PICT model specifying all parameters and their values
 #
 spairQueue: 0,1,2,3
-reducerType: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25
-divLookup: 1, 2
+reducerType: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26
+divLookup: 1, 2, 3, 4
 monTable: 0, 1, 2
 buchberger: 0, 1
 postponeKoszul: 0, 1
@@ -48,7 +48,9 @@ threadCount: 1, 2, 8
 #
 IF [buchberger] = 0 THEN
   [autoTopReduce] = 0 AND
-  [autoTailReduce] = 0;
+  [autoTailReduce] = 0 AND
+  [reducerType] <> 25 AND
+  [reducerType] <> 26;
 
 IF [buchberger] = 1 THEN
   [postponeKoszul] = 0 AND

-- 
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