[mathicgb] 26/393: Added QuadMatrixBuilder for building F4 matrices along with tests of this class.

Doug Torrance dtorrance-guest at moszumanska.debian.org
Fri Apr 3 15:58:26 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 a34360b0f6cc2e1386178ccd2fb91783a18a1cfd
Author: Bjarke Hammersholt Roune <bjarkehr.code at gmail.com>
Date:   Tue Sep 25 22:23:22 2012 +0200

    Added QuadMatrixBuilder for building F4 matrices along with tests of this class.
---
 Makefile.am                        |   5 +-
 src/mathicgb/QuadMatrixBuilder.cpp | 117 ++++++++++++++++++
 src/mathicgb/QuadMatrixBuilder.hpp | 240 +++++++++++++++++++++++++++++++++++++
 src/test/QuadMatrixBuilder.cpp     | 122 +++++++++++++++++++
 4 files changed, 482 insertions(+), 2 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 1cd973b..4c42627 100755
--- a/Makefile.am
+++ b/Makefile.am
@@ -54,7 +54,8 @@ libmathicgb_la_SOURCES = src/mathicgb/BjarkeGeobucket2.cpp				\
   src/mathicgb/stdinc.h src/mathicgb/TournamentReducer.cpp				\
   src/mathicgb/TournamentReducer.hpp src/mathicgb/SigSPairQueue.hpp		\
   src/mathicgb/SigSPairQueue.cpp src/mathicgb/SparseMatrix.hpp			\
-  src/mathicgb/SparseMatrix.cpp
+  src/mathicgb/SparseMatrix.cpp src/mathicgb/QuadMatrixBuilder.hpp		\
+  src/mathicgb/QuadMatrixBuilder.cpp
 
 # When making a distribution file, Automake knows to include all files
 # that are necessary to build the project. EXTRA_DIST specifies files
@@ -84,4 +85,4 @@ test_LIBS=
 unittest_SOURCES=src/test/FreeModuleOrderTest.cpp						\
   src/test/gtestInclude.cpp src/test/testMain.cpp src/test/gb-test.cpp	\
   src/test/ideals.cpp src/test/poly-test.cpp src/test/ideals.hpp		\
-  src/test/SparseMatrix.cpp
+  src/test/SparseMatrix.cpp src/test/QuadMatrixBuilder.cpp
diff --git a/src/mathicgb/QuadMatrixBuilder.cpp b/src/mathicgb/QuadMatrixBuilder.cpp
new file mode 100755
index 0000000..b7dc8d6
--- /dev/null
+++ b/src/mathicgb/QuadMatrixBuilder.cpp
@@ -0,0 +1,117 @@
+#include "stdinc.h"
+#include "QuadMatrixBuilder.hpp"
+
+#include <mathic.h>
+#include <sstream>
+
+namespace {
+  /// Creates a column and updates the associated data structures that
+  /// are passed in. Copies mono - ownership is not taken over. The
+  /// purpose of this function is to avoid code duplication. It is a
+  /// template in order to avoid referring to private types of
+  /// QuadMatrixBuilder.
+  template<class ToMono, class ToCol>
+  QuadMatrixBuilder::ColIndex createCol
+  (const_monomial mono,
+   SparseMatrix& top,
+   SparseMatrix& bottom,
+   ToMono& toMonomial,
+   ToCol& toCol,
+   const PolyRing& ring,
+   const bool left)
+  {
+    MATHICGB_ASSERT(top.colCount() == bottom.colCount());
+    MATHICGB_ASSERT(toMonomial.size() == bottom.colCount());
+    MATHICGB_ASSERT(toCol.find(mono) == toCol.end());
+
+    const QuadMatrixBuilder::ColIndex colCount = top.colCount();
+    if (colCount == std::numeric_limits<QuadMatrixBuilder::ColIndex>::max())
+      throw std::overflow_error("Too many columns in QuadMatrixBuilder");
+
+    toMonomial.reserve(toMonomial.size() + 1);
+    monomial copied = ring.allocMonomial();
+    ring.monomialCopy(mono, copied);
+    try {
+      toCol.insert(std::make_pair
+                   (copied,
+                    QuadMatrixBuilder::LeftRightColIndex(colCount, left)));
+    } catch (...) {
+      ring.freeMonomial(copied);
+      throw;
+    }
+    toMonomial.push_back(copied); // no throw due to reserve
+
+    top.ensureAtLeastThisManyColumns(colCount + 1);
+    bottom.ensureAtLeastThisManyColumns(colCount + 1);
+    return colCount;
+  }
+}
+
+QuadMatrixBuilder::ColIndex QuadMatrixBuilder::createColumnLeft
+(const_monomial monomialToBeCopied) {
+  return createCol
+    (monomialToBeCopied,
+     mTopLeft,
+     mBottomLeft,
+     mMonomialsLeft,
+     mMonomialToCol,
+     ring(),
+     true);
+  MATHICGB_ASSERT(mMonomialToCol.size() == leftColCount() + rightColCount());
+  MATHICGB_ASSERT
+    (findColumn(monomialToBeCopied).leftIndex() == leftColCount() - 1);
+}
+
+QuadMatrixBuilder::ColIndex QuadMatrixBuilder::createColumnRight
+(const_monomial monomialToBeCopied) {
+  return createCol
+    (monomialToBeCopied,
+     mTopRight,
+     mBottomRight,
+     mMonomialsRight,
+     mMonomialToCol,
+     ring(),
+     false);
+  MATHICGB_ASSERT(mMonomialToCol.size() == leftColCount() + rightColCount());
+  MATHICGB_ASSERT
+    (findColumn(monomialToBeCopied).rightIndex() == rightColCount() - 1);
+}
+
+void QuadMatrixBuilder::print(std::ostream& out) const {
+  mathic::ColumnPrinter printer;
+  printer.addColumn(true, "", "");
+  printer.addColumn(true, " | ", "");
+
+  // column monomials
+  out << "Left columns:";
+  for (ColIndex leftCol = 0; leftCol < leftColCount(); ++leftCol) {
+    out << ' ';
+    ring().monomialDisplay(out, monomialOfLeftCol(leftCol), false, true);
+  }
+
+  out << "\nRight columns:";
+  for (ColIndex rightCol = 0; rightCol < rightColCount(); ++rightCol) {
+    out << ' ';
+    ring().monomialDisplay(out, monomialOfRightCol(rightCol), false, true);
+  }
+  out << '\n';
+
+  // left side
+  topLeft().print(printer[0]);
+  printer[0] << '\n';
+  bottomLeft().print(printer[0]);
+
+  // right side
+  topRight().print(printer[1]);
+  printer[1] << '\n';
+  bottomRight().print(printer[1]);
+
+  out << printer;
+}
+
+// String representation intended for debugging.
+std::string QuadMatrixBuilder::toString() const {
+  std::ostringstream out;
+  print(out);
+  return out.str();
+}
diff --git a/src/mathicgb/QuadMatrixBuilder.hpp b/src/mathicgb/QuadMatrixBuilder.hpp
new file mode 100755
index 0000000..18adbaf
--- /dev/null
+++ b/src/mathicgb/QuadMatrixBuilder.hpp
@@ -0,0 +1,240 @@
+#ifndef MATHICGB_QUAD_MATRIX_BUILDER_GUARD
+#define MATHICGB_QUAD_MATRIX_BUILDER_GUARD
+
+#include "SparseMatrix.hpp"
+#include "PolyRing.hpp"
+#include <vector>
+#include <map>
+#include <string>
+#include <ostream>
+
+/** Builder for a set of 4 sub-matrices that fit together and where
+  columns have an associated monomial.
+
+  The sub-matrices are top left, top right, bottom left and bottom
+  right. The interface ensures that these fit together in terms of
+  number of rows and columns so that they could form one bigger
+  matrix.
+
+  Columns have an associated monomial and it is possible to search for
+  the column with a given monomial.
+
+  This matrix is intended to be used while constructing matrices to
+  reduce polynomials using the F4 algorithm of Faugere. */
+class QuadMatrixBuilder {
+ public:
+  typedef SparseMatrix::RowIndex RowIndex;
+  typedef SparseMatrix::ColIndex ColIndex;
+  typedef SparseMatrix::Scalar Scalar;
+
+  QuadMatrixBuilder(const PolyRing& ring):
+    mMonomialToCol(ArbitraryOrdering(ring)) {}
+
+  /// The index of a column that can be either on the left or the
+  /// right side. The largest representable ColIndex is an invalid
+  /// index. This is the default value. The only allowed method to
+  /// call for an invalid index is valid().
+  class LeftRightColIndex {
+  public:
+    LeftRightColIndex():
+      mRawIndex(std::numeric_limits<ColIndex>::max()), mLeft(false) {}
+    LeftRightColIndex(ColIndex index, bool left):
+      mRawIndex(index), mLeft(left) {
+    }
+
+    ColIndex leftIndex() const {
+      MATHICGB_ASSERT(left());
+      return index();
+    }
+
+    ColIndex rightIndex() const {
+      MATHICGB_ASSERT(right());
+      return index();
+    }
+
+    /// Use leftIndex() or rightIndex() instead if you know what side
+    /// you are expecting, as check the side in assert mode.
+    ColIndex index() const {
+      MATHICGB_ASSERT(valid());
+      return mRawIndex;
+    }
+
+    bool left() const {
+      MATHICGB_ASSERT(valid());
+      return mLeft;
+    }
+
+    bool right() const {
+      MATHICGB_ASSERT(valid());
+      return !left();
+    }
+
+    bool valid() const {
+      return mRawIndex != std::numeric_limits<ColIndex>::max();
+    }
+
+  private:
+    ColIndex mRawIndex;
+    bool mLeft;
+  };
+
+  // **** Appending entries to top matrices.
+  // Same interface as SparseMatrix except with two matrices and here
+  // you have to create columns before you can use them.
+
+  void appendEntryTopLeft(ColIndex col, Scalar scalar) {
+    MATHICGB_ASSERT(col < leftColCount());
+    mTopLeft.appendEntry(col, scalar);
+  }
+
+  void appendEntryTopRight(ColIndex col, Scalar scalar) {
+    MATHICGB_ASSERT(col < rightColCount());
+    mTopRight.appendEntry(col, scalar);
+  }
+
+  void appendEntryTop(LeftRightColIndex col, Scalar scalar) {
+    MATHICGB_ASSERT(col.valid());
+    if (col.left())
+      appendEntryTopLeft(col.leftIndex(), scalar);
+    else
+      appendEntryTopRight(col.rightIndex(), scalar);
+  }
+
+  void rowDoneTopLeftAndRight() {
+    mTopLeft.rowDone();
+    mTopRight.rowDone();
+  }
+
+  // **** Appending entries to bottom matrices
+  // Same interface as SparseMatrix except with two matrices and here
+  // you have to create columns before you can use them.
+
+  void appendEntryBottomLeft(ColIndex col, Scalar scalar) {
+    MATHICGB_ASSERT(col < leftColCount());
+    mBottomLeft.appendEntry(col, scalar);
+  }
+
+  void appendEntryBottomRight(ColIndex col, Scalar scalar) {
+    MATHICGB_ASSERT(col < rightColCount());
+    mBottomRight.appendEntry(col, scalar);
+  }
+
+  void appendEntryBottom(LeftRightColIndex col, Scalar scalar) {
+    MATHICGB_ASSERT(col.valid());
+    if (col.left())
+      appendEntryBottomLeft(col.leftIndex(), scalar);
+    else
+      appendEntryBottomRight(col.rightIndex(), scalar);
+  }
+
+  void rowDoneBottomLeftAndRight() {
+    mBottomLeft.rowDone();
+    mBottomRight.rowDone();
+  }
+
+  // *** Creating columns
+  // Unlike the interface for SparseMatrix, here you have to create
+  // columns before you can append entries in those columns. All
+  // passed in monomials are copied so that ownership of the memory is
+  // not taken over.
+
+  /** Creates a new column associated to the monomial
+    monomialToBeCopied to the left matrices. There must not already
+    exist a column for this monomial on the left or on the right. */
+  ColIndex createColumnLeft(const_monomial monomialToBeCopied);
+
+  /** Creates a new column associated to the monomial monomialToBeCopied
+    to the right matrices. There must not already exist a column for
+    this monomial on the left or on the right. */
+  ColIndex createColumnRight(const_monomial monomialToBeCopied);
+
+
+  // *** Querying columns
+
+  // Returns a column for the findThis monomial. Searches on both the
+  // left and right side. Returns an invalid index if no such column
+  // exists.
+  LeftRightColIndex findColumn(const_monomial findThis) const {
+    MonomialToColType::const_iterator it = mMonomialToCol.find(findThis);
+    if (it != mMonomialToCol.end())
+      return it->second;
+    else
+      return LeftRightColIndex();
+  }
+
+  const_monomial monomialOfLeftCol(ColIndex col) const {
+    MATHICGB_ASSERT(col < mMonomialsLeft.size());
+    return mMonomialsLeft[col];
+  }
+
+  const_monomial monomialOfRightCol(ColIndex col) const {
+    MATHICGB_ASSERT(col < mMonomialsRight.size());
+    return mMonomialsRight[col];
+  }
+
+  const_monomial monomialOfCol(LeftRightColIndex col) const {
+    MATHICGB_ASSERT(col.valid());
+    if (col.left())
+      return monomialOfLeftCol(col.leftIndex());
+    else
+      return monomialOfRightCol(col.rightIndex());
+  }
+
+  const SparseMatrix& topLeft() const {return mTopLeft;}
+  const SparseMatrix& topRight() const {return mTopRight;}
+  const SparseMatrix& bottomLeft() const {return mBottomLeft;}
+  const SparseMatrix& bottomRight() const {return mBottomRight;}
+
+  // String representation intended for debugging.
+  void print(std::ostream& out) const;
+
+  // String representation intended for debugging.
+  std::string toString() const;
+
+  const PolyRing& ring() const {
+    // The key comparer object already has a ring reference - we might
+    // as well use that one instead of adding another reference to
+    // this object.
+    return mMonomialToCol.key_comp().ring();
+  }
+
+  ColIndex leftColCount() const {
+    MATHICGB_ASSERT(topLeft().colCount() == bottomLeft().colCount());
+    return topLeft().colCount();
+  }
+
+  ColIndex rightColCount() const {
+    MATHICGB_ASSERT(topRight().colCount() == bottomRight().colCount());
+    return topRight().colCount();
+  }
+
+private:
+  // Store the monomials for each left and right column respectivewy.
+  typedef std::vector<monomial> MonomialsType;
+  MonomialsType mMonomialsLeft;
+  MonomialsType mMonomialsRight;
+
+  /// We need SOME ordering to make std::map work.
+  class ArbitraryOrdering {
+  public:
+    ArbitraryOrdering(const PolyRing& ring): mRing(ring) {}
+    bool operator()(const_monomial a, const_monomial b) const {
+      return mRing.monomialLT(a, b);
+    }
+    const PolyRing& ring() const {return mRing;}
+
+  private:
+    const PolyRing& mRing;
+  };
+  /// Allows fast determination of which column has a given monomial.
+  typedef std::map<const_monomial, LeftRightColIndex, ArbitraryOrdering>
+    MonomialToColType;
+  MonomialToColType mMonomialToCol;
+
+  SparseMatrix mTopLeft;
+  SparseMatrix mTopRight;
+  SparseMatrix mBottomLeft;
+  SparseMatrix mBottomRight;
+};
+
+#endif
diff --git a/src/test/QuadMatrixBuilder.cpp b/src/test/QuadMatrixBuilder.cpp
new file mode 100755
index 0000000..c2dede2
--- /dev/null
+++ b/src/test/QuadMatrixBuilder.cpp
@@ -0,0 +1,122 @@
+#include "mathicgb/stdinc.h"
+
+#include "mathicgb/Poly.hpp"
+#include "mathicgb/PolyRing.hpp"
+#include "mathicgb/QuadMatrixBuilder.hpp"
+#include "mathicgb/io-util.hpp"
+#include <gtest/gtest.h>
+
+namespace {
+  void createColumns(const char* left, const char* right, QuadMatrixBuilder& b)
+  {
+    const PolyRing& ring = b.ring();
+    {
+      Poly p(&b.ring());
+      std::istringstream in(left);
+      p.parse(in);
+      size_t colCount = 0;
+      for (Poly::iterator it = p.begin(); it != p.end(); ++it) {
+        QuadMatrixBuilder::ColIndex col = b.createColumnLeft(it.getMonomial());
+        ASSERT_EQ(colCount, col);
+        ++colCount;
+        // not equal as pointers
+        ASSERT_TRUE(it.getMonomial().unsafeGetRepresentation() !=
+                    b.monomialOfLeftCol(col).unsafeGetRepresentation());
+        ASSERT_TRUE // equal as values
+          (b.ring().monomialEQ(it.getMonomial(), b.monomialOfLeftCol(col)));
+      }
+      ASSERT_EQ(colCount, b.leftColCount());
+    }
+    {
+      Poly p(&b.ring());
+      std::istringstream in(right);
+      p.parse(in);
+      size_t colCount = 0;
+      for (Poly::iterator it = p.begin(); it != p.end(); ++it) {
+        QuadMatrixBuilder::ColIndex col = b.createColumnRight(it.getMonomial());
+        ASSERT_EQ(colCount, col);
+        ++colCount;
+        // not equal as pointers
+        ASSERT_TRUE(it.getMonomial().unsafeGetRepresentation() !=
+                    b.monomialOfRightCol(col).unsafeGetRepresentation());
+        ASSERT_TRUE // equal as values
+          (b.ring().monomialEQ(it.getMonomial(), b.monomialOfRightCol(col)));
+      }
+      ASSERT_EQ(colCount, b.rightColCount());
+    }
+  }
+}
+
+TEST(QuadMatrixBuilder, Empty) {
+  PolyRing ring(2, 0, 0);
+  QuadMatrixBuilder b(ring); // test a builder with no rows and no columns
+  const char* matrixStr = 
+    "Left columns:\n"
+    "Right columns:\n"
+    "matrix with no rows | matrix with no rows\n"
+    "                    |                    \n"
+    "matrix with no rows | matrix with no rows\n";
+  ASSERT_EQ(matrixStr, b.toString());
+}
+
+TEST(QuadMatrixBuilder, Construction) {
+  std::auto_ptr<PolyRing> ring(ringFromString("32003 6 1\n1 1 1 1 1 1"));
+  QuadMatrixBuilder b(*ring);
+  createColumns("a<1>+<0>", "b<0>+c<0>+bc<0>", b);
+
+  // top row: nothing, nothing
+  b.rowDoneTopLeftAndRight();
+
+  // top row: 0#1 1#2, 2#3
+  b.appendEntryTopLeft(0, 1);
+  b.appendEntryTopLeft(1, 2);
+  b.appendEntryTopRight(2, 3);
+  b.rowDoneTopLeftAndRight();
+
+  // bottom row: 1#4, nothing
+  b.appendEntryBottomLeft(1,4);
+  b.rowDoneBottomLeftAndRight();
+
+  // bottom row: nothing, 0#5
+  b.appendEntryBottomRight(0,5);
+  b.rowDoneBottomLeftAndRight();
+
+  // bottom row: nothing, nothing
+  b.rowDoneBottomLeftAndRight();
+
+  const char* matrixStr =
+    "Left columns: a 1\n"
+    "Right columns: b c bc\n"
+    "0:         | 0:    \n"
+    "1: 0#1 1#2 | 1: 2#3\n"
+    "           |       \n"
+    "0: 1#4     | 0:    \n"
+    "1:         | 1: 0#5\n"
+    "2:         | 2:    \n";
+  ASSERT_EQ(matrixStr, b.toString());
+}
+
+TEST(QuadMatrixBuilder, ColumnQuery) {
+  std::auto_ptr<PolyRing> ring(ringFromString("32003 6 1\n1 1 1 1 1 1"));
+  QuadMatrixBuilder b(*ring);
+  createColumns("a<1>+<0>", "b<0>+c<0>+bc<0>", b);
+
+  Poly p(&b.ring());
+  // coefficient 1X=left, 2X=right, 30=not there, % 10 = column index
+  std::istringstream in
+    ("10a<1>+11<0>+20b<0>+21c<0>+22bc<0>+30ab<0>+30e<0>+10a<1>");
+  p.parse(in);
+  for (Poly::iterator it = p.begin(); it != p.end(); ++it) {
+    QuadMatrixBuilder::LeftRightColIndex col = b.findColumn(it.getMonomial());
+    if (it.getCoefficient() / 10 == 3)
+      ASSERT_FALSE(col.valid());
+    else {
+      ASSERT_TRUE(col.valid());
+      ASSERT_EQ(it.getCoefficient() % 10, col.index());
+      if (it.getCoefficient() / 10 == 2)
+        ASSERT_TRUE(col.right());
+      else
+        ASSERT_TRUE(col.left());
+    }
+  }
+}

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