[mathicgb] 96/393: Made some changes to MonomialMap to prepare for using a single concurrent hashtable instead of per-thread hash tables. This (temporarily) has made it fixed-size. Performance is, unexpectedly, better by 1% single-core. This happened when forcing the internal table pointer and mask onto the stack of clients (via a handle). I'm not sure if the cause of the better performance is due to better compiler information (const-on-stack is easy to prove things about for compilers) or just that things are done slightly differently which happens to randomly emit better code.

Doug Torrance dtorrance-guest at moszumanska.debian.org
Fri Apr 3 15:58:39 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 6c3cf91bdcc9ab2a584e0671de809d26ef7cde02
Author: Bjarke Hammersholt Roune <bjarkehr.code at gmail.com>
Date:   Sat Nov 3 16:38:36 2012 +0100

    Made some changes to MonomialMap to prepare for using a single concurrent hashtable instead of per-thread hash tables. This (temporarily) has made it fixed-size. Performance is, unexpectedly, better by 1% single-core. This happened when forcing the internal table pointer and mask onto the stack of clients (via a handle). I'm not sure if the cause of the better performance is due to better compiler information (const-on-stack is easy to prove things about for compilers) or just that th [...]
---
 src/mathicgb/F4MatrixBuilder.cpp   |  56 +++-
 src/mathicgb/F4MatrixBuilder.hpp   |  18 +-
 src/mathicgb/MonomialMap.hpp       | 591 ++++++++++++++++++++++---------------
 src/mathicgb/PolyRing.hpp          |   3 +-
 src/mathicgb/QuadMatrixBuilder.hpp |   6 +
 5 files changed, 431 insertions(+), 243 deletions(-)

diff --git a/src/mathicgb/F4MatrixBuilder.cpp b/src/mathicgb/F4MatrixBuilder.cpp
index 99315f3..36e7382 100755
--- a/src/mathicgb/F4MatrixBuilder.cpp
+++ b/src/mathicgb/F4MatrixBuilder.cpp
@@ -5,7 +5,7 @@
 #include <omp.h>
 #endif
 
-MATHICGB_INLINE QuadMatrixBuilder::LeftRightColIndex
+MATHICGB_NO_INLINE QuadMatrixBuilder::LeftRightColIndex
   F4MatrixBuilder::findOrCreateColumn
 (
   const const_monomial monoA,
@@ -20,7 +20,23 @@ MATHICGB_INLINE QuadMatrixBuilder::LeftRightColIndex
   return createColumn(builder, monoA, monoB);
 }
 
-MATHICGB_INLINE const std::pair<
+MATHICGB_INLINE QuadMatrixBuilder::LeftRightColIndex
+  F4MatrixBuilder::findOrCreateColumn
+(
+  const const_monomial monoA,
+  const const_monomial monoB,
+  const ColSnapshotReader& colMap,
+  QuadMatrixBuilder& builder
+) {
+  MATHICGB_ASSERT(!monoA.isNull());
+  MATHICGB_ASSERT(!monoB.isNull());
+  const auto col = colMap.findProduct(monoA, monoB);
+  if (col == 0)
+    return createColumn(builder, monoA, monoB);
+  return *col;
+}
+
+MATHICGB_NO_INLINE const std::pair<
   QuadMatrixBuilder::LeftRightColIndex,
   QuadMatrixBuilder::LeftRightColIndex
 > F4MatrixBuilder::findOrCreateTwoColumns
@@ -49,6 +65,27 @@ MATHICGB_INLINE const std::pair<
   return colPair;
 }
 
+MATHICGB_INLINE const std::pair<
+  QuadMatrixBuilder::LeftRightColIndex,
+  QuadMatrixBuilder::LeftRightColIndex
+> F4MatrixBuilder::findOrCreateTwoColumns
+(
+  const const_monomial monoA1,
+  const const_monomial monoA2,
+  const const_monomial monoB,
+  const ColSnapshotReader& colMap,
+  QuadMatrixBuilder& builder
+) {
+  MATHICGB_ASSERT(!monoA1.isNull());
+  MATHICGB_ASSERT(!monoA2.isNull());
+  MATHICGB_ASSERT(!monoB.isNull());
+  MATHICGB_ASSERT(!ring().monomialEQ(monoA1, monoA2));
+  auto colPair = colMap.findTwoProducts(monoA1, monoA2, monoB);
+  if (colPair.first == 0 || colPair.second == 0)
+    return findOrCreateTwoColumns(monoA1, monoA2, monoB, builder);
+  return std::make_pair(*colPair.first, *colPair.second);
+}
+
 F4MatrixBuilder::F4MatrixBuilder(
   const PolyBasis& basis,
   const int threadCount,
@@ -334,9 +371,10 @@ void F4MatrixBuilder::appendRowBottom(
   // todo: eliminate the code-duplication between here and appendRowTop.
   MATHICGB_ASSERT(!multiple.isNull());
   MATHICGB_ASSERT(&builder != 0);
+  const ColSnapshotReader colMap(builder.columnToIndexMap());
 
   for (auto it  = begin; it != end; ++it) {
-    const auto col = findOrCreateColumn(it.getMonomial(), multiple, builder);
+    const auto col = findOrCreateColumn(it.getMonomial(), multiple, colMap, builder);
     const auto origScalar = it.getCoefficient();
     MATHICGB_ASSERT(origScalar != 0);
     const auto possiblyNegated =
@@ -356,10 +394,12 @@ void F4MatrixBuilder::appendRowTop(
   MATHICGB_ASSERT(&poly != 0);
   MATHICGB_ASSERT(&builder != 0);
 
+  QuadMatrixBuilder::ColSnapshotReader colMap(builder.columnToIndexMap());
+
   auto it = poly.begin();
   const auto end = poly.end();
   if ((std::distance(it, end) % 2) == 1) {
-    const auto col = findOrCreateColumn(it.getMonomial(), multiple, builder);
+    const auto col = findOrCreateColumn(it.getMonomial(), multiple, colMap, builder);
 	MATHICGB_ASSERT(it.getCoefficient() < std::numeric_limits<Scalar>::max());
     MATHICGB_ASSERT(it.getCoefficient());
     builder.appendEntryTop(col, static_cast<Scalar>(it.getCoefficient()));
@@ -380,7 +420,7 @@ void F4MatrixBuilder::appendRowTop(
     ++it;
 
     const auto colPair =
-      findOrCreateTwoColumns(mono1, mono2, multiple, builder);
+      findOrCreateTwoColumns(mono1, mono2, multiple, colMap, builder);
     builder.appendEntryTop(colPair.first, scalar1);
     builder.appendEntryTop(colPair.second, scalar2);
   }
@@ -414,6 +454,8 @@ void F4MatrixBuilder::appendRowBottom(
   ++itA;
   ++itB;
 
+  const ColSnapshotReader colMap(builder.columnToIndexMap());
+
   const const_monomial mulA = task.multiply;
   const const_monomial mulB = task.sPairMultiply;
   while (true) {
@@ -431,8 +473,8 @@ void F4MatrixBuilder::appendRowBottom(
 
     coefficient coeff = 0;
     LeftRightColIndex col;
-    const auto colA = findOrCreateColumn(itA.getMonomial(), mulA, builder);
-    const auto colB = findOrCreateColumn(itB.getMonomial(), mulB, builder);
+    const auto colA = findOrCreateColumn(itA.getMonomial(), mulA, colMap, builder);
+    const auto colB = findOrCreateColumn(itB.getMonomial(), mulB, colMap, builder);
     const auto cmp = ring().monomialCompare
       (builder.monomialOfCol(colA), builder.monomialOfCol(colB));
     if (cmp != LT) {
diff --git a/src/mathicgb/F4MatrixBuilder.hpp b/src/mathicgb/F4MatrixBuilder.hpp
index 48b3220..8138cc6 100755
--- a/src/mathicgb/F4MatrixBuilder.hpp
+++ b/src/mathicgb/F4MatrixBuilder.hpp
@@ -66,6 +66,8 @@ public:
   const PolyRing& ring() const {return mBuilder.ring();}
 
 private:
+  typedef const QuadMatrixBuilder::ColSnapshotReader ColSnapshotReader;
+
   /** 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. */
@@ -97,18 +99,30 @@ private:
     QuadMatrixBuilder& builder
   );
 
-  MATHICGB_INLINE LeftRightColIndex findOrCreateColumn
+  MATHICGB_NO_INLINE LeftRightColIndex findOrCreateColumn
     (const_monomial monoA, const_monomial monoB, QuadMatrixBuilder& builder);
+  MATHICGB_INLINE LeftRightColIndex findOrCreateColumn(
+    const_monomial monoA,
+    const_monomial monoB,
+    const ColSnapshotReader& colMap,
+    QuadMatrixBuilder& builder);
 
+  MATHICGB_NO_INLINE const std::pair<LeftRightColIndex, LeftRightColIndex>
+  findOrCreateTwoColumns(
+    const const_monomial monoA1,
+    const const_monomial monoA2,
+    const const_monomial monoB,
+    QuadMatrixBuilder& builder
+  );
   MATHICGB_INLINE const std::pair<LeftRightColIndex, LeftRightColIndex>
   findOrCreateTwoColumns(
     const const_monomial monoA1,
     const const_monomial monoA2,
     const const_monomial monoB,
+    const ColSnapshotReader& colMap,
     QuadMatrixBuilder& builder
   );
 
-
   const int mThreadCount;
   monomial mTmp;
   std::vector<RowTask> mTodo;
diff --git a/src/mathicgb/MonomialMap.hpp b/src/mathicgb/MonomialMap.hpp
index f3c399e..037b5cc 100755
--- a/src/mathicgb/MonomialMap.hpp
+++ b/src/mathicgb/MonomialMap.hpp
@@ -2,40 +2,225 @@
 #define MATHICGB_MONOMIAL_MAP_GUARD
 
 #include "PolyRing.hpp"
-#include <limits>
-
-#if defined(MATHICGB_USE_STD_HASH) && defined(MATHICGB_USE_CUSTOM_HASH)
-#error Only select one kind of hash table
-#endif
-
-// set default hash table type if nothing has been specified
-#if !defined(MATHICGB_USE_STD_HASH) && !defined(MATHICGB_USE_CUSTOM_HASH)
-#define MATHICGB_USE_CUSTOM_HASH
-#endif
-
-#ifdef MATHICGB_USE_CUSTOM_HASH
 #include <memtailor.h>
+#include <limits>
 #include <vector>
 #include <algorithm>
-#elif defined(MATHICGB_USE_STD_HASH)
-#include <unordered_map>
-#else
-#include <map>
-#endif
 
-/** A mapping from monomials to MapToType. The interface is the same as
-  for STL maps. The interface is not complete. Add methods you need when
-  you need it.
-*/
+/// A mapping from monomials to MapToType. The interface is the same as
+/// for STL maps. The interface is not complete. Add methods you need when
+/// you need it.
 template<class MapToType>
 class MonomialMap;
 
+template<class MTT>
+class FixedSizeMonomialMap {
+public:
+  typedef MTT mapped_type;
+  typedef std::pair<const_monomial, mapped_type> value_type;
+
+private:
+  struct Node {
+    Node* next;
+    mapped_type value;
+    exponent mono[1];
+  };
+
+  static HashValue computeHashMask(const size_t requestedBucketCount) {
+    // round request up to nearest power of 2.
+    size_t pow2 = 1;
+    while (pow2 < requestedBucketCount && 2 * pow2 != 0)
+      pow2 *= 2;
+    MATHICGB_ASSERT(pow2 > 0 && (pow2 & (pow2 - 1)) == 0); // power of two
+
+    // If casting to a hash value overflows, then we get the maximum
+    // possible number of buckets based on the range of the hash
+    // value type. Only unsigned overflow is defined, so we need
+    // to assert that the hash type is unsigned.
+    static_assert(!std::numeric_limits<HashValue>::is_signed, "");
+    const auto hashToIndexMask = static_cast<HashValue>(pow2 - 1);
+    MATHICGB_ASSERT(pow2 == hashMaskToBucketCount(hashToIndexMask));
+    return hashToIndexMask;
+  }
+
+  static size_t hashMaskToBucketCount(const HashValue mask) {
+    const auto count = static_cast<size_t>(mask) + 1u; // should be power of 2
+    MATHICGB_ASSERT(count > 0 && (count & (count - 1)) == 0); 
+    return count;
+  }
+
+  static size_t sizeofNode(const PolyRing& ring) {
+    return sizeof(Node) - sizeof(exponent) + ring.maxMonomialByteSize();
+  }
+
+public:
+  size_t bucketCount() const {
+    return hashMaskToBucketCount(mHashToIndexMask);
+  }
+
+  FixedSizeMonomialMap(
+    const size_t requestedBucketCount,
+    const PolyRing& ring
+  ):
+    mHashToIndexMask(computeHashMask(requestedBucketCount)),
+    mBuckets(new Node*[hashMaskToBucketCount(mHashToIndexMask)]),
+    mRing(ring),
+    mNodeAlloc(sizeofNode(ring)),
+    mEntryCount(0)
+  {
+    std::fill_n(mBuckets, bucketCount(), static_cast<Node*>(0));
+  }
+
+  ~FixedSizeMonomialMap() {
+    delete[] mBuckets;
+  }
+
+  FixedSizeMonomialMap(
+    const size_t requestedBucketCount,
+    const FixedSizeMonomialMap& map
+  ):
+    mHashToIndexMask(computeHashMask(requestedBucketCount)),
+    mBuckets(new Node*[hashMaskToBucketCount(mHashToIndexMask)]),
+    mRing(map.ring()),
+    mNodeAlloc(sizeofNode(map.ring())),
+    mEntryCount(0)
+  {
+    for (size_t bucket = 0; bucket < map.bucketCount(); ++bucket)
+      for (Node* node = map.mBuckets[bucket]; node != 0; node = node->next)
+        insert(std::make_pair(node->mono, node->value));
+    /*
+    todo: use this code once we have a move constructor for mNodeAlloc.
+    // Move nodes from current table into new table
+    decltype(mBuckets) newTable(newTableSize);
+    HashValue newHashToIndexMask = static_cast<HashValue>(newTableSize - 1);
+    const auto tableEnd = mBuckets.end();
+    for (auto tableIt = mBuckets.begin(); tableIt != tableEnd; ++tableIt) {
+      Node* node = *tableIt;
+      while (node != 0) {
+        const size_t index =
+          mRing.monomialHashValue(node->mono) & newHashToIndexMask;
+        MATHICGB_ASSERT(index < newTable.size());
+        Node* const next = node->next;
+        node->next = newTable[index];
+        newTable[index] = node;
+        node = next;
+      }
+    }
+
+    // Move newly calculated table into place
+    mBucketsSize = newTableSize;      
+    mBuckets = std::move(newTable);
+    mHashToIndexMask = newHashToIndexMask;
+    mGrowWhenThisManyEntries = newGrowWhenThisManyEntries;
+
+    MATHICGB_ASSERT(mBucketsSize < mGrowWhenThisManyEntries);
+    */
+  }
+
+  const PolyRing& ring() const {return mRing;}
+  size_t size() const {return mEntryCount;}
+
+  const mapped_type* find(const const_monomial mono) const {
+    const HashValue monoHash = mRing.monomialHashValue(mono);
+    const Node* node = bucketAtIndex(hashToIndex(monoHash));
+    for (; node != 0; node = node->next) {
+      // To my surprise, it seems to be faster to comment out this branch.
+      // I guess the hash table has too few collisions to make it worth it.
+      //if (monoHash != mRing.monomialHashValue(node->mono))
+      //  continue;
+      if (mRing.monomialEqualHintTrue(mono, node->mono))
+        return &node->value;
+    }
+    return 0;
+  }
+
+  MATHICGB_INLINE const mapped_type* findProduct(
+    const const_monomial a,
+    const const_monomial b
+  ) const {
+    const HashValue abHash = mRing.monomialHashOfProduct(a, b);
+    const Node* node = bucketAtIndex(hashToIndex(abHash));
+    for (; node != 0; node = node->next) {
+      // To my surprise, it seems to be faster to comment out this branch.
+      // I guess the hash table has too few collisions to make it worth it.
+      //if (abHash != mRing.monomialHashValue(node->mono))
+      //  continue;
+      if (mRing.monomialIsProductOfHintTrue(a, b, node->mono))
+        return &node->value;
+    }
+    return 0;
+  }
+
+  /// As findProduct but looks for a1*b and a2*b at one time.
+  MATHICGB_INLINE
+  std::pair<const mapped_type*, const mapped_type*> findTwoProducts(
+    const const_monomial a1,
+    const const_monomial a2,
+    const const_monomial b
+  ) const {
+    const HashValue a1bHash = mRing.monomialHashOfProduct(a1, b);
+    const HashValue a2bHash = mRing.monomialHashOfProduct(a2, b);
+    const Node* const node1 = bucketAtIndex(hashToIndex(a1bHash));
+    const Node* const node2 = bucketAtIndex(hashToIndex(a2bHash));
+
+    if (node1 != 0 && node2 != 0 && mRing.monomialIsTwoProductsOfHintTrue
+      (a1, a2, b, node1->mono, node2->mono)
+    )
+      return std::make_pair(&node1->value, &node2->value);
+    else
+      return std::make_pair(findProduct(a1, b), findProduct(a2, b));
+  }
+
+  void insert(const value_type& value) {
+    Node* node = static_cast<Node*>(mNodeAlloc.alloc());
+    const size_t index = hashToIndex(mRing.monomialHashValue(value.first));
+    {
+      Monomial nodeTmp(node->mono);
+      ring().monomialCopy(value.first, nodeTmp);
+    }
+    new (&node->value) mapped_type(value.second);
+    node->next = bucketAtIndex(index);
+    mBuckets[index] = node;
+    ++mEntryCount;
+  }
+
+  void clear() {
+    std::fill_n(mBuckets, bucketCount(), static_cast<Node*>(0));
+    mNodeAlloc.freeAllBuffers();
+    mEntryCount = 0;
+  }
+
+private:
+  size_t hashToIndex(HashValue hash) const {
+    const auto index = hash & mHashToIndexMask;
+    MATHICGB_ASSERT(index == hash % bucketCount());
+    return index;
+  }
+
+  Node* bucketAtIndex(size_t index) {
+    MATHICGB_ASSERT(index < bucketCount());
+    return mBuckets[index];
+  }
+
+  const Node* bucketAtIndex(size_t index) const {
+    MATHICGB_ASSERT(index < bucketCount());
+    return mBuckets[index];
+  }
+
+  const HashValue mHashToIndexMask;
+  Node** const mBuckets;
+  const PolyRing& mRing;
+  memt::BufferPool mNodeAlloc; // nodes are allocated from here.
+  size_t mEntryCount;
+};
+
+
+
 namespace MonomialMapInternal {
   // The map type MapClass is defined here. This is here in
   // this namespace to avoid cluttering the class definition with
   // a lot of ifdef's.
 
-#ifdef MATHICGB_USE_CUSTOM_HASH
   template<class MTT>
   class MapClass {
   public:
@@ -51,7 +236,7 @@ namespace MonomialMapInternal {
     };
 
   public:
-    MapClass(const PolyRing& ring):
+    MapClass(const PolyRing& ring, size_t bucketCount = 400000):
       mRing(ring),
       mTable(),
       mNodeAlloc(sizeof(Node) - sizeof(exponent) + ring.maxMonomialByteSize())
@@ -62,58 +247,23 @@ namespace MonomialMapInternal {
       growTable();
     }
 
-    Map& map() {return *this;}
-    const Map& map() const {return *this;}
     const PolyRing& ring() const {return mRing;}
 
-    mapped_type* find(const_monomial mono) {
-      const HashValue monoHash = mRing.monomialHashValue(mono);
-      Node* node = entry(hashToIndex(monoHash));
-      for (; node != 0; node = node->next) {
-        // To my surprise, it seems to be faster to comment out this branch.
-        // I guess the hash table has too few collisions to make it worth it.
-        //if (monoHash != mRing.monomialHashValue(node->mono))
-        //  continue;
-        if (mRing.monomialEqualHintTrue(mono, node->mono))
-          return &node->value;
-      }
-      return 0;
-    }
-
-    MATHICGB_INLINE mapped_type* findProduct(
+    MATHICGB_INLINE const mapped_type* findProduct(
       const const_monomial a,
       const const_monomial b
-    ) {
-      const HashValue abHash = mRing.monomialHashOfProduct(a, b);
-      Node* node = entry(hashToIndex(abHash));
-      for (; node != 0; node = node->next) {
-        // To my surprise, it seems to be faster to comment out this branch.
-        // I guess the hash table has too few collisions to make it worth it.
-        //if (abHash != mRing.monomialHashValue(node->mono))
-        //  continue;
-        if (mRing.monomialIsProductOfHintTrue(a, b, node->mono))
-          return &node->value;
-      }
-      return 0;
+    ) const {
+      return reader().findProduct(a, b);
     }
 
     /// As findProduct but looks for a1*b and a2*b at one time.
-    MATHICGB_INLINE std::pair<mapped_type*, mapped_type*> findTwoProducts(
+    MATHICGB_INLINE
+    std::pair<const mapped_type*, const mapped_type*> findTwoProducts(
       const const_monomial a1,
       const const_monomial a2,
       const const_monomial b
-    ) {
-      const HashValue a1bHash = mRing.monomialHashOfProduct(a1, b);
-      const HashValue a2bHash = mRing.monomialHashOfProduct(a2, b);
-      Node* const node1 = entry(hashToIndex(a1bHash));
-      Node* const node2 = entry(hashToIndex(a2bHash));
-
-      if (node1 != 0 && node2 != 0 && mRing.monomialIsTwoProductsOfHintTrue
-        (a1, a2, b, node1->mono, node2->mono)
-      )
-        return std::make_pair(&node1->value, &node2->value);
-      else
-        return std::make_pair(findProduct(a1, b), findProduct(a2, b));
+    ) const {
+      return reader().findTwoProducts(a1, a2, b);
     }
 
     void insert(const value_type& value) {
@@ -140,6 +290,102 @@ namespace MonomialMapInternal {
 
     size_t size() const {return mEntryCount;}
 
+    class MapReader {
+    public:
+      const mapped_type* find(const const_monomial mono) const {
+        const HashValue monoHash = mRing.monomialHashValue(mono);
+        const Node* node = entry(hashToIndex(monoHash));
+        for (; node != 0; node = node->next) {
+          // To my surprise, it seems to be faster to comment out this branch.
+          // I guess the hash table has too few collisions to make it worth it.
+          //if (monoHash != mRing.monomialHashValue(node->mono))
+          //  continue;
+          if (mRing.monomialEqualHintTrue(mono, node->mono))
+            return &node->value;
+        }
+        return 0;
+      }
+
+      const PolyRing& ring() {return mRing;}
+
+      size_t bucketCount() const {
+        MATHICGB_ASSERT(mHashToIndexMask <
+          std::numeric_limits<decltype(mHashToIndexMask)>::max());
+        return mHashToIndexMask + 1;
+      }
+
+      MATHICGB_INLINE const mapped_type* findProduct(
+        const const_monomial a,
+        const const_monomial b
+      ) const {
+        const HashValue abHash = mRing.monomialHashOfProduct(a, b);
+        const Node* node = entry(hashToIndex(abHash));
+        for (; node != 0; node = node->next) {
+          // To my surprise, it seems to be faster to comment out this branch.
+          // I guess the hash table has too few collisions to make it worth it.
+          //if (abHash != mRing.monomialHashValue(node->mono))
+          //  continue;
+          if (mRing.monomialIsProductOfHintTrue(a, b, node->mono))
+            return &node->value;
+        }
+        return 0;
+      }
+
+      /// As findProduct but looks for a1*b and a2*b at one time.
+      MATHICGB_INLINE
+      std::pair<const mapped_type*, const mapped_type*> findTwoProducts(
+        const const_monomial a1,
+        const const_monomial a2,
+        const const_monomial b
+      ) const {
+        const HashValue a1bHash = mRing.monomialHashOfProduct(a1, b);
+        const HashValue a2bHash = mRing.monomialHashOfProduct(a2, b);
+        const Node* const node1 = entry(hashToIndex(a1bHash));
+        const Node* const node2 = entry(hashToIndex(a2bHash));
+
+        if (node1 != 0 && node2 != 0 && mRing.monomialIsTwoProductsOfHintTrue
+          (a1, a2, b, node1->mono, node2->mono)
+        )
+          return std::make_pair(&node1->value, &node2->value);
+        else
+          return std::make_pair(findProduct(a1, b), findProduct(a2, b));
+      }
+
+    private:
+      friend class MapClass<MTT>;
+      size_t hashToIndex(const HashValue hash) const {
+        const auto index = hash & mHashToIndexMask;
+        MATHICGB_ASSERT(index == hash % bucketCount());
+        return index;
+      }
+
+      const Node* entry(const size_t index) const {
+        MATHICGB_ASSERT(index < bucketCount());
+        return mTable[index];
+      }
+
+      MapReader(
+        const PolyRing& ring,
+        const Node* const* const table,
+        const HashValue mHashToIndexMask
+      ):
+        mRing(ring),
+        mTable(table),
+        mHashToIndexMask(mHashToIndexMask) {}
+
+      const PolyRing& mRing;
+      const Node* const* const mTable;
+      const HashValue mHashToIndexMask;
+    };
+
+    const mapped_type* find(const const_monomial mono) const {
+      return reader().find(mono);
+    }
+
+    const MapReader reader() const {
+      return MapReader(ring(), mTable.data(), mHashToIndexMask);
+    }
+
   private:
     size_t hashToIndex(HashValue hash) const {
       const auto index = hash & mHashToIndexMask;
@@ -205,205 +451,86 @@ namespace MonomialMapInternal {
     std::vector<Node*> mTable;
     memt::BufferPool mNodeAlloc; // nodes are allocated from here.
   };
-
-#elif defined(MATHICGB_USE_STD_HASH)
-  class Hash {
-  public:
-    Hash(const PolyRing& ring): mRing(ring) {}
-    size_t operator()(const_monomial m) const {
-      return mRing.monomialHashValue(m);
-    }
-    const PolyRing& ring() const {return mRing;}
-
-  private:
-    const PolyRing& mRing;
-  };
-
-  class Equal {
-  public:
-    Equal(const PolyRing& ring): mRing(ring) {}
-    size_t operator()(const_monomial a, const_monomial b) const {
-      return mRing.monomialEQ(a, b);
-    }
-    const PolyRing& ring() const {return mRing;}
-
-  private:
-    const PolyRing& mRing;
-  };
-
-  // This has to be a template to support rebind().
-  template<class T>
-  class TemplateHashAllocator {
-  public:
-    typedef T value_type;
-    typedef T* pointer;
-    typedef T& reference;
-    typedef const T* const_pointer;
-    typedef const T& const_reference;
-    typedef ::size_t size_type;
-    typedef ::ptrdiff_t difference_type;
-
-    template<class T2>
-    struct rebind {
-      typedef TemplateHashAllocator<T2> other;
-    };
-
-    TemplateHashAllocator() {}
-    TemplateHashAllocator(memt::Arena& arena): mArena(arena) {}
-    template<class X>
-    TemplateHashAllocator(const TemplateHashAllocator<X>& a):
-      mArena(a.arena()) {}
-    TemplateHashAllocator(const TemplateHashAllocator<T>& a):
-      mArena(a.arena()) {}
-
-    pointer address(reference x) {return &x;}
-    const_pointer address(const_reference x) const {return &x;}
-    pointer allocate(size_type n, void* hint = 0) {
-      return static_cast<pointer>(mArena.alloc(sizeof(T) * n));
-    }
-    void deallocate(pointer p, size_t n) {}
-    size_type max_size() const {return std::numeric_limits<size_type>::max();}
-    void construct(pointer p, const_reference val) {new (p) T(val);}
-    void destroy(pointer p) {p->~T();}
-    memt::Arena& arena() const {return mArena;}
-
-  private:
-    mutable memt::Arena& mArena;
-  };
-
-  template<class MTT>
-  class MapClass {
-  public:
-    typedef TemplateHashAllocator<std::pair<const const_monomial, MTT>>
-      HashAllocator;
-    typedef std::unordered_map<const_monomial, MTT, Hash, Equal, HashAllocator>
-      Map;
-    typedef typename Map::iterator iterator;
-    typedef typename Map::const_iterator const_iterator;
-    typedef typename Map::value_type value_type;
-
-    MapClass(const PolyRing& ring):
-      mArena(),
-      mMap(100, Hash(ring), Equal(ring), HashAllocator(mArena)),
-      mTmp(ring.allocMonomial())
-    {
-      mMap.max_load_factor(0.3f);
-    }
-
-    ~MapClass() {
-      ring().freeMonomial(mTmp);
-    }
-
-    Map& map() {return mMap;}
-    const Map& map() const {return mMap;}
-    const PolyRing& ring() const {return mMap.key_eq().ring();}
-
-    value_type* findProduct(const_monomial a, const_monomial b) {
-      ring().setGivenHash(mTmp, ring().monomialHashOfProduct(a, b));
-      size_t bucket = mMap.bucket(mTmp);
-      auto stop = mMap.end(bucket);
-      for (auto it = mMap.begin(bucket); it != stop; ++it)
-        if (ring().monomialIsProductOf(a, b, it->first))
-          return &*it;
-      return 0;
-    }
-
-  private:
-    memt::Arena mArena;
-    Map mMap;
-    monomial mTmp;
-  };
-#elif defined(MATHICGB_USE_CUSTOM_HASH)
-#else
-  /// 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;
-  };
-
-  template<class MTT>
-  class MapClass {
-  public:
-    typedef std::map<const_monomial, MTT, ArbitraryOrdering> Map;
-
-    MapClass(const PolyRing& ring): mMap(ArbitraryOrdering(ring)) {}
-    Map& map() {return mMap;}
-    const Map& map() const {return mMap;}
-    const PolyRing& ring() const {return mMap.key_cmp().ring();}
-
-  private:
-    Map mMap;
-  };
-#endif
 }
 
+
 template<class MTT>
 class MonomialMap {
 public:
   typedef MTT mapped_type;
-  typedef MonomialMapInternal::MapClass<MTT> MapType;
+  //typedef MonomialMapInternal::MapClass<MTT> MapType;
+  typedef FixedSizeMonomialMap<MTT> MapType;
 
   //typedef typename MapType::Map::iterator iterator;
   //typedef typename MapType::Map::const_iterator const_iterator;
-  typedef typename MapType::Map::value_type value_type;
+  typedef typename MapType::value_type value_type;
+
+  /// A snapshot of a map. Later updates to the map may
+  /// or may not ever become reflected in this snapshot. The acquire/release
+  /// overhead for reading from the table is only performed once per
+  /// snapshot while it is performed every time when reading directly
+  /// from the map.
+  class SnapshotReader {
+  public:
+    SnapshotReader(const MonomialMap<MTT>& map): mMap(&map.mMap) {}
+    void update(const MonomialMap<MTT>& map) {mMap = &map.mMap;}
 
-  MonomialMap(const PolyRing& ring): mMap(ring) {}
+    const mapped_type* find(const_monomial m) const {
+      return mMap->find(m);
+    }
 
-/*  iterator begin() {return map().begin();}
-  const_iterator begin() const {return map().begin();}
-  iterator end() {return map().end();}
-  const_iterator end() const {return map().end();}*/
+    const mapped_type* findProduct(
+      const const_monomial a,
+      const const_monomial b
+    ) const {
+      return mMap->findProduct(a, b);
+    }
 
-  mapped_type* find(const_monomial m) {return mMap.find(m);}
+    MATHICGB_INLINE
+    std::pair<const mapped_type*, const mapped_type*> findTwoProducts(
+      const const_monomial a1,
+      const const_monomial a2,
+      const const_monomial b
+    ) const {
+      return mMap->findTwoProducts(a1, a2, b);
+    }
 
-  mapped_type* findProduct(const_monomial a, const_monomial b) {
-    return mMap.findProduct(a, b);
-  }
+  private:
+    SnapshotReader(const FixedSizeMonomialMap<MTT>& map): mMap(&map) {}
+    const FixedSizeMonomialMap<MTT>* mMap;
+  };
 
-  MATHICGB_INLINE std::pair<mapped_type*, mapped_type*> findTwoProducts(
-    const const_monomial a1,
-    const const_monomial a2,
-    const const_monomial b
-  ) {
-    return mMap.findTwoProducts(a1, a2, b);
-  }
+  MonomialMap(const PolyRing& ring): mMap(200 * 1000, ring) {}
 
   const mapped_type* find(const_monomial m) const {
-    return const_cast<MonomialMap&>(*this).find(m);
+    return mMap.find(m);
   }
 
-  const mapped_type* findProduct(const_monomial a, const_monomial b) const {
-    return const_cast<MonomialMap&>(*this).findProduct(a, b);
+  const mapped_type* findProduct(
+    const const_monomial a,
+    const const_monomial b
+  ) const {
+    return mMap.findProduct(a, b);
   }
 
-  MATHICGB_INLINE const std::pair<const mapped_type*, const mapped_type*>
-  findTwoProducts(
+  MATHICGB_INLINE
+  std::pair<const mapped_type*, const mapped_type*> findTwoProducts(
     const const_monomial a1,
     const const_monomial a2,
     const const_monomial b
   ) const {
-    return const_cast<MonomialMap&>(*this).findTwoProducts(a1, a2, b);
+    return mMap.findTwoProducts(a1, a2, b);
   }
 
-  size_t size() const {return map().size();}
-  void clear() {map().clear();}
+  size_t size() const {return mMap.size();}
+  void clear() {mMap.clear();}
   void insert(const value_type& val) {
-    map().insert(val);
+    mMap.insert(val);
   }
 
   inline const PolyRing& ring() const {return mMap.ring();}
 
 private:
-  typename MapType::Map& map() {return mMap.map();}
-  const typename MapType::Map& map() const {return mMap.map();}
-
   MapType mMap;
 };
 
diff --git a/src/mathicgb/PolyRing.hpp b/src/mathicgb/PolyRing.hpp
index 0f357c4..ddb260f 100755
--- a/src/mathicgb/PolyRing.hpp
+++ b/src/mathicgb/PolyRing.hpp
@@ -699,8 +699,7 @@ MATHICGB_INLINE bool PolyRing::monomialIsTwoProductsOfHintTrue(
     orOfXor |= (A1B ^ (A1 + B)) | (A2B ^ (A2 + B));
   }
   MATHICGB_ASSERT((orOfXor == 0) ==
-    monomialIsProductOf(a1, b, a1b) &&
-    monomialIsProductOf(a2, b, a2b));
+    (monomialIsProductOf(a1, b, a1b) && monomialIsProductOf(a2, b, a2b)));
 
   return orOfXor == 0;
 }
diff --git a/src/mathicgb/QuadMatrixBuilder.hpp b/src/mathicgb/QuadMatrixBuilder.hpp
index 7b050d8..71d9d4a 100755
--- a/src/mathicgb/QuadMatrixBuilder.hpp
+++ b/src/mathicgb/QuadMatrixBuilder.hpp
@@ -183,6 +183,12 @@ class QuadMatrixBuilder {
 
   // *** Querying columns
 
+  typedef const MonomialMap<LeftRightColIndex>::SnapshotReader
+    ColSnapshotReader;
+  const MonomialMap<LeftRightColIndex>& columnToIndexMap() const {
+    return mMonomialToCol;
+  }
+
   /** Returns a column for the findThis monomial. Searches on both the
     left and right side. Returns an invalid index if no such column
     exists. */

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