[mathicgb] 176/393: Refactoring to eliminate the code duplication for computing a top/bottom projection inside F4MatrixProjection.

Doug Torrance dtorrance-guest at moszumanska.debian.org
Fri Apr 3 15:58:56 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 0401bf0164058d4ddf571bc1a2e5f20206412802
Author: Bjarke Hammersholt Roune <bjarkehr.code at gmail.com>
Date:   Mon Feb 18 20:33:47 2013 +0100

    Refactoring to eliminate the code duplication for computing a top/bottom projection inside F4MatrixProjection.
---
 src/mathicgb/F4MatrixBuilder2.cpp   |   2 +-
 src/mathicgb/F4MatrixProjection.cpp | 379 ++++++++++++++++++------------------
 src/mathicgb/F4MatrixProjection.hpp |  47 ++---
 3 files changed, 198 insertions(+), 230 deletions(-)

diff --git a/src/mathicgb/F4MatrixBuilder2.cpp b/src/mathicgb/F4MatrixBuilder2.cpp
index 0551718..7b00296 100755
--- a/src/mathicgb/F4MatrixBuilder2.cpp
+++ b/src/mathicgb/F4MatrixBuilder2.cpp
@@ -198,7 +198,7 @@ void F4MatrixBuilder2::buildMatrixAndClear(QuadMatrix& quadMatrix) {
     projection.addColumn(p.first, p.second, mIsColumnToLeft[p.first]);
   }
 
-  quadMatrix = projection.makeProjectionAndClear();
+  quadMatrix = projection.makeAndClear(mMemoryQuantum);
   threadData.clear();
 
 #ifdef MATHICGB_DEBUG
diff --git a/src/mathicgb/F4MatrixProjection.cpp b/src/mathicgb/F4MatrixProjection.cpp
index 9b1ad26..82728d0 100644
--- a/src/mathicgb/F4MatrixProjection.cpp
+++ b/src/mathicgb/F4MatrixProjection.cpp
@@ -38,193 +38,80 @@ void F4MatrixProjection::addColumn(
   monoGuard.dismiss();
 }
 
-void F4MatrixProjection::setupRowProjection() {
-  mTopRowProjectFrom.resize(mLeftMonomials.size());
-
-  const auto noReducer = std::numeric_limits<RowIndex>::max();
-  F4ProtoMatrix::Row noRow = {};
-  noRow.indices = 0;
-  const auto noCol = std::numeric_limits<SparseMatrix::ColIndex>::max();
-  const auto modulus = static_cast<SparseMatrix::Scalar>(ring().charac());
-
-  const auto end = mMatrices.end();
-  for (auto it = mMatrices.begin(); it != end; ++it) {
-    auto& matrix = **it;
-    const auto rowCount = matrix.rowCount();
-    for (RowIndex r = 0; r < rowCount; ++r) {
-      const auto row = matrix.row(r);
-      if (row.entryCount == 0)
-        continue;
-
-      // Determine leading (minimum index) left entry.
-      const auto lead = [&] {
-        for (SparseMatrix::ColIndex col = 0; col < row.entryCount; ++col) {
-          auto const translated = mColProjectTo[row.indices[col]];
-          if (translated.isLeft)
-            return std::make_pair(col, translated.index);
-        }
-        return std::make_pair(noCol, noCol);
-      }();
-      // Decide if this should be a reducer or reducee row.
-      if (lead.second == noCol) {
-        const RowProjectFrom p = {1, row};
-        mBottomRowProjectFrom.push_back(p); // no left entries
-        continue;
-      }
-      MATHICGB_ASSERT(row.scalars != 0 || row.externalScalars != 0);
-
-      const auto reducer = mTopRowProjectFrom[lead.second].row;
-      if (
-        reducer.entryCount != 0 && // already have a reducer and...
-        reducer.entryCount < row.entryCount // ...it is sparser/better
-      ) {
-        const RowProjectFrom p = {1, row};
-        mBottomRowProjectFrom.push_back(p);
-      } else {
-        if (reducer.entryCount != 0) {
-          const RowProjectFrom p = {1, reducer};
-          mBottomRowProjectFrom.push_back(p);
-        }
-        const auto leadScalar = row.scalars != 0 ? row.scalars[lead.first] :
-          static_cast<SparseMatrix::Scalar>
-            (row.externalScalars[lead.first]);
-        MATHICGB_ASSERT(leadScalar != 0);
-        const auto inverse = leadScalar == 1 ?
-          1 : modularInverse(leadScalar, modulus);
-        const RowProjectFrom p = {inverse, row};
-        mTopRowProjectFrom[lead.second] = p;
-      }
-    }
-  }
-#ifdef MATHICGB_DEBUG
-  for (size_t  i = 0; i < mTopRowProjectFrom.size(); ++i) {
-    const auto p = mTopRowProjectFrom[i];
-    MATHICGB_ASSERT(p.row.entryCount > 0);
-    MATHICGB_ASSERT(p.multiplyBy != 0);
-
-    // Find leading left entry.
-    ColIndex col = 0;
-    while (!mColProjectTo[p.row.indices[col]].isLeft) {
-      ++col;
-      MATHICGB_ASSERT(col < p.row.entryCount);
-    }
-    const auto projected = mColProjectTo[p.row.indices[col]];
-
-    // The leading left entry of row i should be in column i.
-    MATHICGB_ASSERT(projected.index == i);
-
-    // After multiplication, the leading left scalar should be 1.
-    const auto leadScalar = p.row.scalars != 0 ?
-      p.row.scalars[col] : static_cast<Scalar>(p.row.externalScalars[col]);
-    MATHICGB_ASSERT(modularProduct(leadScalar, p.multiplyBy, modulus) == 1);
-  }
-  for (size_t  i = 0; i < mBottomRowProjectFrom.size(); ++i) {
-    const auto p = mBottomRowProjectFrom[i];
-    MATHICGB_ASSERT(p.row.entryCount > 0);
-    MATHICGB_ASSERT(p.multiplyBy != 0);
-  }
-#endif
-}
-
-void F4MatrixProjection::projectRows(
-  SparseMatrix&& in,
-  SparseMatrix& top,
-  SparseMatrix& bottom
-) {
-  const auto modulus = static_cast<Scalar>(ring().charac());
+struct RowData : F4ProtoMatrix::Row {
+  RowData(): F4ProtoMatrix::Row() {}
+  RowData(const F4ProtoMatrix::Row& row): F4ProtoMatrix::Row(row) {}
+};
 
-  top.clear();
-  bottom.clear();
+typedef std::pair<RowData, SparseMatrix::Scalar> RowProjectFrom;
 
-  const auto rowCountTop =
-    static_cast<SparseMatrix::RowIndex>(mTopRows.size());
-  for (SparseMatrix::RowIndex toRow = 0; toRow < rowCountTop; ++toRow) {
-    top.appendRow(in, mTopRows[toRow].row);
-    if (mTopRows[toRow].multiplyBy != 1)
-      top.multiplyRow(toRow, mTopRows[toRow].multiplyBy, modulus);
-  }
 
-  const auto rowCountBottom =
-    static_cast<SparseMatrix::RowIndex>(mBottomRows.size());
-  for (SparseMatrix::RowIndex toRow = 0; toRow < rowCountBottom; ++toRow) {
-    bottom.appendRow(in, mBottomRows[toRow].row);
-    if (mBottomRows[toRow].multiplyBy != 1)
-        bottom.multiplyRow(toRow, mBottomRows[toRow].multiplyBy, modulus);
-  }
+template<class Row>
+class F4MatrixProjection::TopBottom {
+public:
+  typedef std::pair<Row, Scalar> RowMultiple;
+  typedef std::vector<RowMultiple> RowVector;
 
-  in.clear();
-}
-
-void F4MatrixProjection::setupRowProjectionLate(
-  const SparseMatrix& left,
-  const SparseMatrix& right
-) {
-  const auto leftColCount = static_cast<ColIndex>(mLeftMonomials.size());
-  const auto modulus = static_cast<Scalar>(ring().charac());
-  const auto noRow = std::numeric_limits<ColIndex>::max();
+  TopBottom(const size_t leftColCount, const PolyRing& ring):
+    mModulus(static_cast<Scalar>(ring.charac())),
+    mTopRows(leftColCount)
   {
-    const RowProjectFromLate init = {0, noRow};
-    mTopRows.resize(leftColCount, init);
+    MATHICGB_ASSERT(ring.charac() <= std::numeric_limits<Scalar>::max());
+    MATHICGB_ASSERT(leftColCount <= std::numeric_limits<ColIndex>::max());
   }
 
-  MATHICGB_ASSERT(left.computeColCount() == leftColCount);
-  MATHICGB_ASSERT(left.rowCount() >= leftColCount);
-  MATHICGB_ASSERT(left.rowCount() == right.rowCount());
-
-  std::vector<SparseMatrix::ColIndex> topEntryCounts(leftColCount);
-
-  const auto rowCount = left.rowCount();
-  for (SparseMatrix::RowIndex row = 0; row < rowCount; ++row) {
-    const auto leftEntryCount = left.entryCountInRow(row);
-    const auto entryCount = leftEntryCount + right.entryCountInRow(row);
-    MATHICGB_ASSERT(entryCount >= leftEntryCount); // no overflow
-    if (entryCount == 0)
-      continue; // ignore zero rows
-    if (leftEntryCount == 0) {
-      RowProjectFromLate p = {1, row};
-      mBottomRows.push_back(p); // can't be top/reducer
-      continue;
+  void addRow(const Row& row, ColIndex leadIndex, Scalar leadScalar) {
+    if (row.entryCount == 0)
+      return; // Skip zero rows.
+    if (leadIndex == std::numeric_limits<ColIndex>::max()) {
+      // this row has no left entries, so it cannot be a top row.
+      mBottomRows.push_back(RowMultiple(row, 1));
+      return;
     }
-    const auto lead = left.rowBegin(row).index();
-    if (mTopRows[lead].row != noRow && topEntryCounts[lead] < entryCount) {
-      RowProjectFromLate p = {1, row};
-      mBottomRows.push_back(p); // other reducer better
+
+    const auto currentTop = mTopRows[leadIndex].first;
+    if (
+      currentTop.entryCount != 0 && // already have a reducer and...
+      currentTop.entryCount < row.entryCount // ...it is sparser/better
+    ) {
+      mBottomRows.push_back(RowMultiple(row, 1));
     } else {
-      if (mTopRows[lead].row != noRow) {
-        RowProjectFromLate p = {1, mTopRows[lead].row};
-        mBottomRows.push_back(p);
-      }
-      topEntryCounts[lead] = entryCount;
-      mTopRows[lead].row = row; // do scalar .first later
+      if (currentTop.entryCount != 0)
+        mBottomRows.push_back(std::make_pair(currentTop, 1));
+      MATHICGB_ASSERT(leadScalar != 0);
+      const auto inverse = leadScalar == 1 ? // 1 is a common case
+        1 : modularInverse(leadScalar, mModulus);
+      mTopRows[leadIndex] = RowMultiple(row, inverse);
     }
   }
 
-  for (SparseMatrix::RowIndex r = 0; r < leftColCount; ++r) {
-    const auto row = mTopRows[r].row;
-    MATHICGB_ASSERT(row != noRow);
-    MATHICGB_ASSERT(left.entryCountInRow(row) > 0);
-    MATHICGB_ASSERT(left.rowBegin(row).index() == r);
-    MATHICGB_ASSERT(left.rowBegin(row).scalar() != 0);
-    MATHICGB_ASSERT(topEntryCounts[r] ==
-      left.entryCountInRow(row) + right.entryCountInRow(row));
-
-    const auto leadScalar = left.rowBegin(row).scalar();
-    mTopRows[r].multiplyBy = leadScalar == 1 ? 1 : // 1 is the common case
-      modularInverse(leadScalar, modulus);
-  }
-
 #ifdef MATHICGB_DEBUG
-  for (SparseMatrix::RowIndex r = 0; r < mBottomRows.size(); ++r) {
-    const auto row = mBottomRows[r].row;
-    MATHICGB_ASSERT(
-      left.entryCountInRow(row) + right.entryCountInRow(row) > 0);
-    MATHICGB_ASSERT(mBottomRows[r].multiplyBy == 1);
+  bool debugAssertValid() {
+    auto check = [](RowMultiple r) {
+      MATHICGB_ASSERT(r.first.entryCount > 0);
+      MATHICGB_ASSERT(r.second != 0);
+    };
+    std::for_each(mTopRows.begin(), mTopRows.end(), check);
+    std::for_each(mBottomRows.begin(), mBottomRows.end(), check);
+    return true;
   }
 #endif
-}
 
-// Utility class for building a left/right projection.
-struct F4MatrixProjection::LeftRight {
+  Scalar modulus() const {return mModulus;}
+  const RowVector& top() const {return mTopRows;}
+  const RowVector& bottom() const {return mBottomRows;}
+
+  RowVector moveTop() {return mTopRows;}
+  RowVector moveBottom() {return mBottomRows;}
+
+private:
+  const Scalar mModulus;
+  RowVector mTopRows;
+  RowVector mBottomRows;
+};
+
+class F4MatrixProjection::LeftRight {
+public:
   typedef F4ProtoMatrix::ExternalScalar ExternalScalar;
   typedef F4ProtoMatrix::Row Row;
 
@@ -243,10 +130,11 @@ struct F4MatrixProjection::LeftRight {
     mRight.clear();
   }
 
-  void appendRowsPermuted(const std::vector<RowProjectFrom>& rows) {
+  template<class Pair>
+  void appendRowsPermuted(const std::vector<Pair>& rows) {
     const auto end = rows.end();
     for (auto it = rows.begin(); it != end; ++it)
-      appendRow(it->row, it->multiplyBy);
+      appendRow(it->first, it->second);
   }
 
   void appendRows(const std::vector<F4ProtoMatrix*>& preBlocks) {
@@ -330,34 +218,139 @@ private:
   SparseMatrix mRight;
 };
 
-QuadMatrix F4MatrixProjection::makeProjectionAndClear() {
+QuadMatrix F4MatrixProjection::makeAndClear(const size_t quantum) {
+  if (true)
+    return makeAndClearOneStep(quantum);
+  else
+    return makeAndClearTwoStep(quantum);
+}
+
+QuadMatrix F4MatrixProjection::makeAndClearOneStep(const size_t quantum) {
+  // Construct top/bottom row permutation
+  TopBottom<F4ProtoMatrix::Row> tb(mLeftMonomials.size(), ring());
+  const auto end = mMatrices.end();
+  for (auto it = mMatrices.begin(); it != end; ++it) {
+    const auto& matrix = **it;
+    const auto rowCount = matrix.rowCount();
+    for (RowIndex r = 0; r < rowCount; ++r) {
+      const auto& row = matrix.row(r); // const ref keeps temporary alive
+      if (row.entryCount == 0)
+        continue; // ignore zero rows
+
+      // *** Look for leading left entry
+      ColIndex lead = 0;
+      for (; lead < row.entryCount; ++lead) {
+        MATHICGB_ASSERT(row.indices[lead] < mColProjectTo.size());
+        auto const projected = mColProjectTo[row.indices[lead]];
+        if (projected.isLeft) {
+          const auto leadScalar = row.scalars != 0 ?
+            row.scalars[lead] :
+            static_cast<Scalar>(row.externalScalars[lead]);
+          tb.addRow(row, projected.index, leadScalar);
+          goto done;
+        }
+      }
+      // Did not find any left entry.
+      tb.addRow(row, std::numeric_limits<ColIndex>::max(), 0);
+done:;
+    }
+  }
+  tb.debugAssertValid();
+
+  // Split left/right and top/bottom simultaneously
+  LeftRight top(mColProjectTo, ring(), quantum);
+  top.appendRowsPermuted(tb.moveTop());
+
+  LeftRight bottom(mColProjectTo, ring(), 0);
+  bottom.appendRowsPermuted(tb.moveBottom());
+
+  // Move the data into place
   QuadMatrix qm;
+  qm.ring = &ring();
+  qm.leftColumnMonomials = std::move(mLeftMonomials);
+  qm.rightColumnMonomials = std::move(mRightMonomials);
+
+  qm.topLeft = top.moveLeft();
+  qm.topRight = top.moveRight();
+  qm.bottomLeft = bottom.moveLeft();
+  qm.bottomRight = bottom.moveRight();
 
-  const size_t quantum = 0; // todo: set quantum from parameter
+  return std::move(qm);
+}
 
-  if (true) {
-    setupRowProjection();
-    {
-      LeftRight top(mColProjectTo, ring(), 0);
-      top.appendRowsPermuted(mTopRowProjectFrom);
-      qm.topLeft = top.moveLeft();
-      qm.topRight = top.moveRight();
+namespace {
+  // Helper function for F4MatrixProjection::makeAndClearTwoStep
+  template<class TopBottom>
+  std::pair<SparseMatrix, SparseMatrix> projectRows(
+    const TopBottom& tb,
+    size_t quantum,
+    SparseMatrix&& in
+  ) {
+    const auto modulus = tb.modulus();
+
+    SparseMatrix top(quantum);
+    const auto topRows = tb.top();
+    const auto rowCountTop =
+      static_cast<SparseMatrix::RowIndex>(topRows.size());
+    for (SparseMatrix::RowIndex toRow = 0; toRow < rowCountTop; ++toRow) {
+      top.appendRow(in, topRows[toRow].first.index);
+      if (topRows[toRow].second != 1)
+        top.multiplyRow(toRow, topRows[toRow].second, modulus);
     }
-    {
-      LeftRight bottom(mColProjectTo, ring(), 0);
-      bottom.appendRowsPermuted(mBottomRowProjectFrom);
-      qm.bottomLeft = bottom.moveLeft();
-      qm.bottomRight = bottom.moveRight();
+
+    SparseMatrix bottom(quantum);
+    const auto bottomRows = tb.bottom();
+    const auto rowCountBottom =
+      static_cast<SparseMatrix::RowIndex>(bottomRows.size());
+    for (SparseMatrix::RowIndex toRow = 0; toRow < rowCountBottom; ++toRow) {
+      bottom.appendRow(in, bottomRows[toRow].first.index);
+      if (bottomRows[toRow].second != 1)
+          bottom.multiplyRow(toRow, bottomRows[toRow].second, modulus);
     }
-  } else {
-    LeftRight lr(mColProjectTo, ring(), 0);
-    lr.appendRows(mMatrices);
-    setupRowProjectionLate(lr.left(), lr.right());
-    projectRows(lr.moveLeft(), qm.topLeft, qm.bottomLeft);
-    projectRows(lr.moveRight(), qm.topRight, qm.bottomRight);
+
+    in.clear();
+    return std::make_pair(std::move(top), std::move(bottom));
   }
+}
+
+QuadMatrix F4MatrixProjection::makeAndClearTwoStep(const size_t quantum) {
+  // Split whole matrix into left/right
+  LeftRight lr(mColProjectTo, ring(), quantum);
+  lr.appendRows(mMatrices);
+
+  // Construct top/bottom matrix permutation
+  struct Row {
+    RowIndex index;
+    ColIndex entryCount;
+  };
+  TopBottom<Row> tb(mLeftMonomials.size(), ring());
+  const auto rowCount = lr.left().rowCount();
+  for (SparseMatrix::RowIndex row = 0; row < rowCount; ++row) {
+    const auto leftEntryCount = lr.left().entryCountInRow(row);
+    const auto entryCount = leftEntryCount + lr.right().entryCountInRow(row);
+    MATHICGB_ASSERT(entryCount >= leftEntryCount); // no overflow
+    if (entryCount == 0)
+      continue; // ignore zero rows
+
+    const Row r = {row, entryCount};
+    if (leftEntryCount == 0)
+      tb.addRow(r, std::numeric_limits<ColIndex>::max(), 0);
+    else {
+      const auto entry = lr.left().rowBegin(row);
+      tb.addRow(r, entry.index(), entry.scalar());
+    }
+  }
+  tb.debugAssertValid();
+
+  QuadMatrix qm;
+  auto left = projectRows(tb, quantum, lr.moveLeft());
+  auto right = projectRows(tb, quantum, lr.moveRight());
 
   qm.ring = &ring();
+  qm.topLeft = std::move(left.first);
+  qm.bottomLeft = std::move(left.second);
+  qm.topRight = std::move(right.first);
+  qm.bottomRight = std::move(right.second);
   qm.leftColumnMonomials = std::move(mLeftMonomials);
   qm.rightColumnMonomials = std::move(mRightMonomials);
   return std::move(qm);
diff --git a/src/mathicgb/F4MatrixProjection.hpp b/src/mathicgb/F4MatrixProjection.hpp
index d198bd9..c34c75f 100644
--- a/src/mathicgb/F4MatrixProjection.hpp
+++ b/src/mathicgb/F4MatrixProjection.hpp
@@ -21,56 +21,31 @@ public:
   // No reference to mono is retained.
   void addColumn(ColIndex index, const_monomial mono, const bool isLeft);
 
-  QuadMatrix makeProjectionAndClear();
+  QuadMatrix makeAndClear(const size_t quantum);
 
   const PolyRing& ring() const {return mRing;}
 
 private:
-  struct LeftRight;
+  QuadMatrix makeAndClearOneStep(const size_t quantum);
+  QuadMatrix makeAndClearTwoStep(const size_t quantum);
 
-  std::vector<F4ProtoMatrix*> mMatrices;
+  // Utility class for building a left/right projection.
+  class LeftRight;
+
+  // Utility class for building a top/bottom projection.
+  template<class Row>
+  class TopBottom;
 
-  // *** Projection of columns
+  // This is for projection of columns
   struct ColProjectTo {
     ColIndex index;
     bool isLeft;
   };
   std::vector<ColProjectTo> mColProjectTo;
 
-  // *** Projection: Simultaneously do let/right and row permutation
-  void setupRowProjection();
-  struct RowProjectFrom {
-    Scalar multiplyBy;
-    F4ProtoMatrix::Row row;
-  };
-  std::vector<RowProjectFrom> mTopRowProjectFrom;
-  std::vector<RowProjectFrom> mBottomRowProjectFrom;
-
-  // *** Projection: Do left/right, then permute rows
-  void setupRowProjectionLate(
-    const SparseMatrix& left,
-    const SparseMatrix& right
-  );
-  struct RowProjectFromLate {
-    Scalar multiplyBy;
-    RowIndex row;
-  };
-  void projectRows(
-    SparseMatrix&& in,
-    SparseMatrix& top,
-    SparseMatrix& bottom
-  );
-  std::vector<RowProjectFromLate> mTopRows;
-  std::vector<RowProjectFromLate> mBottomRows;
-
-
-
-
-
-
+  std::vector<F4ProtoMatrix*> mMatrices;
   std::vector<monomial> mLeftMonomials;
   std::vector<monomial> mRightMonomials;
-
   const PolyRing& mRing;
 };
 

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