[mathicgb] 81/393: Parallelized the sorting and reordering of matrices. Also added a set of macroes that give a way to tell the optimizer extra information, such as saying that two pointers are not aliases.
Doug Torrance
dtorrance-guest at moszumanska.debian.org
Fri Apr 3 15:58:35 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 0921cbe90474fe396f66694724c5ecd862824e3b
Author: Bjarke Hammersholt Roune <bjarkehr.code at gmail.com>
Date: Thu Oct 25 20:58:23 2012 +0200
Parallelized the sorting and reordering of matrices. Also added a set of macroes that give a way to tell the optimizer extra information, such as saying that two pointers are not aliases.
---
src/mathicgb/F4MatrixBuilder.cpp | 3 +-
src/mathicgb/F4MatrixReducer.cpp | 9 ++--
src/mathicgb/GroebnerBasis.hpp | 18 ++++----
src/mathicgb/MonTableDivList.hpp | 4 +-
src/mathicgb/Poly.cpp | 2 +-
src/mathicgb/PolyRing.hpp | 8 ++--
src/mathicgb/QuadMatrix.cpp | 6 ++-
src/mathicgb/QuadMatrix.hpp | 3 +-
src/mathicgb/QuadMatrixBuilder.cpp | 71 +++++++++++++++++++++++++++++
src/mathicgb/QuadMatrixBuilder.hpp | 5 +++
src/mathicgb/SPairs.cpp | 2 +-
src/mathicgb/SparseMatrix.hpp | 2 +-
src/mathicgb/stdinc.h | 91 +++++++++++++++++++++++++++++++-------
src/test/FreeModuleOrderTest.cpp | 6 +--
14 files changed, 180 insertions(+), 50 deletions(-)
diff --git a/src/mathicgb/F4MatrixBuilder.cpp b/src/mathicgb/F4MatrixBuilder.cpp
index f7da87d..fed4dfa 100755
--- a/src/mathicgb/F4MatrixBuilder.cpp
+++ b/src/mathicgb/F4MatrixBuilder.cpp
@@ -225,8 +225,7 @@ void F4MatrixBuilder::buildMatrixAndClear(QuadMatrix& matrix) {
#endif
- mBuilder.sortColumnsLeft(mBasis.order());
- mBuilder.sortColumnsRight(mBasis.order());
+ mBuilder.sortColumnsLeftRightParallel(mBasis.order(), mThreadCount);
mBuilder.buildMatrixAndClear(matrix);
}
diff --git a/src/mathicgb/F4MatrixReducer.cpp b/src/mathicgb/F4MatrixReducer.cpp
index ca658ff..bdae9d7 100755
--- a/src/mathicgb/F4MatrixReducer.cpp
+++ b/src/mathicgb/F4MatrixReducer.cpp
@@ -523,13 +523,10 @@ void myReduceToEchelonForm5
MATHICGB_ASSERT(reduced.colCount() == colCount);
size_t const row = nextReducers[i].second;
-#ifdef MATHICGB_DEBUG
- size_t const col = nextReducers[i].first;
-#endif
- MATHICGB_ASSERT(col == nextReducers[i].first);
- MATHICGB_ASSERT(columnHasPivot[col]);
+ MATHICGB_ASSERT(static_cast<bool>
+ (columnHasPivot[nextReducers[i].first]));
MATHICGB_ASSERT(dense[row].colCount() == colCount);
- MATHICGB_ASSERT(dense[row][col] == 1); // already normalized
+ MATHICGB_ASSERT(dense[row][nextReducers[i].first] == 1); // already normalized
MATHICGB_ASSERT(reduced.rowCount() == i);
MATHICGB_ASSERT(!isPivotRow[row]);
diff --git a/src/mathicgb/GroebnerBasis.hpp b/src/mathicgb/GroebnerBasis.hpp
index 51e291b..b0c928c 100644
--- a/src/mathicgb/GroebnerBasis.hpp
+++ b/src/mathicgb/GroebnerBasis.hpp
@@ -189,18 +189,18 @@ private:
inline int GroebnerBasis::ratioCompare(size_t a, size_t b) const {
if (mUseRatioRank) {
-#ifdef DEBUG
+#ifdef MATHICGB_DEBUG
int const value =
order().signatureCompare(getSigLeadRatio(a), getSigLeadRatio(b));
#endif
if (mRatioRanks[a] < mRatioRanks[b]) {
- ASSERT(value == LT);
+ MATHICGB_ASSERT_NO_ASSUME(value == LT);
return LT;
} else if (mRatioRanks[a] > mRatioRanks[b]) {
- ASSERT(value == GT);
+ MATHICGB_ASSERT_NO_ASSUME(value == GT);
return GT;
} else {
- ASSERT(value == EQ);
+ MATHICGB_ASSERT_NO_ASSUME(value == EQ);
return EQ;
}
} else {
@@ -208,7 +208,7 @@ inline int GroebnerBasis::ratioCompare(size_t a, size_t b) const {
ring().monomialDivideToNegative(getSignature(b), getLeadMonomial(b), mTmp);
ring().monomialMultTo(mTmp, getLeadMonomial(a));
int value = order().signatureCompare(getSignature(a), mTmp);
- ASSERT(value ==
+ MATHICGB_ASSERT(value ==
order().signatureCompare(getSigLeadRatio(a), getSigLeadRatio(b)));
return value;
}
@@ -222,19 +222,19 @@ inline int GroebnerBasis::StoredRatioCmp::compare(size_t be) const {
#endif
GroebnerBasis::Rank otherRank = mBasis.ratioRank(be);
if (mRatioRank < otherRank) {
- ASSERT(value == LT);
+ MATHICGB_ASSERT_NO_ASSUME(value == LT);
return LT;
} else if (mRatioRank > otherRank) {
- ASSERT(value == GT);
+ MATHICGB_ASSERT_NO_ASSUME(value == GT);
return GT;
} else {
- ASSERT(value == EQ);
+ MATHICGB_ASSERT_NO_ASSUME(value == EQ);
return EQ;
}
} else {
mBasis.ring().monomialMult(mRatio, mBasis.getLeadMonomial(be), mTmp);
int value = mBasis.order().signatureCompare(mTmp, mBasis.getSignature(be));
- ASSERT(value ==
+ MATHICGB_ASSERT(value ==
mBasis.order().signatureCompare(mRatio, mBasis.getSigLeadRatio(be)));
return value;
}
diff --git a/src/mathicgb/MonTableDivList.hpp b/src/mathicgb/MonTableDivList.hpp
index 17ad7be..4f3e628 100644
--- a/src/mathicgb/MonTableDivList.hpp
+++ b/src/mathicgb/MonTableDivList.hpp
@@ -49,7 +49,7 @@ public:
size_t getVarCount() const {return _varCount;}
- NO_PINLINE Exponent getExponent(const Monomial& m, size_t var) const {
+ Exponent getExponent(const Monomial& m, size_t var) const {
++_expQueryCount;
return R->monomialExponent(m, var);
}
@@ -67,7 +67,7 @@ public:
return true;
if (getExponent(b, var) < getExponent(a, var))
return false;
- }
+ }
return false;
}
diff --git a/src/mathicgb/Poly.cpp b/src/mathicgb/Poly.cpp
index ca4f30e..9ab4221 100755
--- a/src/mathicgb/Poly.cpp
+++ b/src/mathicgb/Poly.cpp
@@ -108,7 +108,7 @@ void Poly::makeMonic() {
R->coefficientReciprocalTo(c);
for (auto i = coeffs.begin(); i != coeffs.end(); i++)
R->coefficientMultTo(*i, c);
- MATHICGB_ASSERT(R->coefficientIsOne(getLeadCoefficient()))
+ MATHICGB_ASSERT(R->coefficientIsOne(getLeadCoefficient()));
}
bool operator==(const Poly &a, const Poly &b)
diff --git a/src/mathicgb/PolyRing.hpp b/src/mathicgb/PolyRing.hpp
index be6c4fa..b81be5c 100755
--- a/src/mathicgb/PolyRing.hpp
+++ b/src/mathicgb/PolyRing.hpp
@@ -56,7 +56,7 @@ T modularInverse(T a, T modulus) {
}
MATHICGB_ASSERT(x >= 1);
MATHICGB_ASSERT(x < modulus);
- MATHICGB_ASSERT((static_cast<uint64>(origA) * x) % modulus == 1);
+ MATHICGB_ASSERT_NO_ASSUME((static_cast<uint64>(origA) * x) % modulus == 1);
return x;
}
@@ -665,11 +665,9 @@ inline bool PolyRing::monomialIsProductOfHintTrue(
std::memcpy(&AB, &ab[i], 8);
orOfXor |= AB ^ (A + B);
}
- MATHICGB_ASSERT((orOfXor == 0) == monomialIsProductOf(a, b, ab))
+ MATHICGB_ASSERT((orOfXor == 0) == monomialIsProductOf(a, b, ab));
-
- return orOfXor == 0;
-
+ return orOfXor == 0;
}
inline bool PolyRing::monomialIsProductOf(
diff --git a/src/mathicgb/QuadMatrix.cpp b/src/mathicgb/QuadMatrix.cpp
index ae13b61..a820c35 100755
--- a/src/mathicgb/QuadMatrix.cpp
+++ b/src/mathicgb/QuadMatrix.cpp
@@ -5,8 +5,10 @@
#include <sstream>
#include <mathic.h>
-#ifdef MATHICGB_DEBUG
bool QuadMatrix::debugAssertValid() const {
+#ifndef MATHICGB_DEBUG
+ return true;
+#else
MATHICGB_ASSERT(topLeft.colCount() == bottomLeft.colCount());
MATHICGB_ASSERT(topLeft.rowCount() == topRight.rowCount());
MATHICGB_ASSERT(topLeft.colCount() == leftColumnMonomials.size());
@@ -15,8 +17,8 @@ bool QuadMatrix::debugAssertValid() const {
MATHICGB_ASSERT(bottomRight.rowCount() == bottomLeft.rowCount());
MATHICGB_ASSERT(bottomRight.colCount() == rightColumnMonomials.size());
return true;
-}
#endif
+}
void QuadMatrix::print(std::ostream& out) const {
MATHICGB_ASSERT(debugAssertValid());
diff --git a/src/mathicgb/QuadMatrix.hpp b/src/mathicgb/QuadMatrix.hpp
index d7282ad..12dceff 100755
--- a/src/mathicgb/QuadMatrix.hpp
+++ b/src/mathicgb/QuadMatrix.hpp
@@ -47,9 +47,8 @@ public:
/// TODO: Actually only coarsely sorts the top rows right now.
QuadMatrix toCanonical() const;
-#ifdef MATHICGB_DEBUG
+ /// Asserts internal invariants if asserts are turned on.
bool debugAssertValid() const;
-#endif
private:
QuadMatrix(const QuadMatrix&); // not available
diff --git a/src/mathicgb/QuadMatrixBuilder.cpp b/src/mathicgb/QuadMatrixBuilder.cpp
index ecda6d8..73033f5 100755
--- a/src/mathicgb/QuadMatrixBuilder.cpp
+++ b/src/mathicgb/QuadMatrixBuilder.cpp
@@ -134,6 +134,45 @@ namespace {
const FreeModuleOrder& mOrder;
};
+ std::vector<SparseMatrix::ColIndex> sortColumnMonomialsAndMakePermutation(
+ const FreeModuleOrder& order,
+ std::vector<monomial>& monomials
+ ) {
+ typedef SparseMatrix::ColIndex ColIndex;
+ MATHICGB_ASSERT(monomials.size() <= std::numeric_limits<ColIndex>::max());
+ const ColIndex colCount = static_cast<ColIndex>(monomials.size());
+ // Monomial needs to be non-const as we are going to put these
+ // monomials back into the vector of monomials which is not const.
+ std::vector<std::pair<monomial, ColIndex>> columns;
+ columns.reserve(colCount);
+ for (ColIndex col = 0; col < colCount; ++col)
+ columns.push_back(std::make_pair(monomials[col], col));
+ std::sort(columns.begin(), columns.end(), ColumnComparer(order));
+
+ // Apply sorting permutation to monomials. This is why it is necessary to
+ // copy the values in monomial out of there: in-place application of a
+ // permutation is messy.
+ MATHICGB_ASSERT(columns.size() == colCount);
+ MATHICGB_ASSERT(monomials.size() == colCount);
+ for (size_t col = 0; col < colCount; ++col) {
+ MATHICGB_ASSERT(col == 0 || order.signatureCompare
+ (columns[col - 1].first, columns[col].first) == GT);
+ monomials[col] = columns[col].first;
+ }
+
+ // Construct permutation of indices to match permutation of monomials
+ std::vector<ColIndex> permutation(colCount);
+ for (ColIndex col = 0; col < colCount; ++col) {
+ // The monomial for column columns[col].second is now the
+ // monomial for col, so we need the inverse map for indices.
+ permutation[columns[col].second] = col;
+ }
+
+ return std::move(permutation);
+ }
+
+
+
// The purpose of this function is to avoid code duplication for
// left/right variants.
void sortColumns
@@ -185,6 +224,38 @@ void QuadMatrixBuilder::sortColumnsRight(const FreeModuleOrder& order) {
sortColumns(order, mMonomialsRight, mTopRight, mBottomRight);
}
+void QuadMatrixBuilder::sortColumnsLeftRightParallel(
+ const FreeModuleOrder& order,
+ int threadCount
+) {
+ std::vector<ColIndex> leftPermutation;
+ std::vector<ColIndex> rightPermutation;
+
+#pragma omp parallel for num_threads(threadCount) schedule(static)
+ for (OMPIndex i = 0; i < 2; ++i) {
+ if (i == 0)
+ leftPermutation =
+ sortColumnMonomialsAndMakePermutation(order, mMonomialsLeft);
+ else
+ rightPermutation =
+ sortColumnMonomialsAndMakePermutation(order, mMonomialsRight);
+ }
+
+#pragma omp parallel for num_threads(threadCount) schedule(dynamic)
+ for (OMPIndex i = 0; i < 4; ++i) {
+ if (i == 0)
+ mTopRight.applyColumnMap(rightPermutation);
+ else if (i == 1)
+ mBottomRight.applyColumnMap(rightPermutation);
+ else if (i == 2)
+ mTopLeft.applyColumnMap(leftPermutation);
+ else {
+ MATHICGB_ASSERT(i == 3);
+ mBottomLeft.applyColumnMap(leftPermutation);
+ }
+ }
+}
+
void QuadMatrixBuilder::print(std::ostream& out) const {
mathic::ColumnPrinter printer;
printer.addColumn(true, "", "");
diff --git a/src/mathicgb/QuadMatrixBuilder.hpp b/src/mathicgb/QuadMatrixBuilder.hpp
index 9e07100..8992d23 100755
--- a/src/mathicgb/QuadMatrixBuilder.hpp
+++ b/src/mathicgb/QuadMatrixBuilder.hpp
@@ -165,6 +165,11 @@ class QuadMatrixBuilder {
this monomial on the left or on the right. */
LeftRightColIndex createColumnRight(const_monomial monomialToBeCopied);
+ /// As calling sortColumnsLeft() and sortColumnsRight(), but performs
+ /// the operations in parallel using up to threadCount threads.
+ void sortColumnsLeftRightParallel
+ (const FreeModuleOrder& order, int threadCount);
+
/** Sorts the left columns to be decreasing with respect to
order. Also updates the column indices already in the matrix to
reflect the new ordering. */
diff --git a/src/mathicgb/SPairs.cpp b/src/mathicgb/SPairs.cpp
index d39d720..ee3e277 100755
--- a/src/mathicgb/SPairs.cpp
+++ b/src/mathicgb/SPairs.cpp
@@ -529,7 +529,7 @@ bool SPairs::advancedBuchbergerLcmCriterionSlow(size_t a, size_t b) const {
} else {
// At this point we have found an edge between something a node to
// a and a node connected to b. So a and b are connected.
- ASSERT(graph[i].second != node.second)
+ ASSERT(graph[i].second != node.second);
applies = true;
break;
}
diff --git a/src/mathicgb/SparseMatrix.hpp b/src/mathicgb/SparseMatrix.hpp
index 57beae0..426b937 100755
--- a/src/mathicgb/SparseMatrix.hpp
+++ b/src/mathicgb/SparseMatrix.hpp
@@ -276,7 +276,7 @@ public:
private:
- NO_INLINE void growEntryCapacity();
+ MATHICGB_NO_INLINE void growEntryCapacity();
/// Contains information about a row in the matrix.
struct Row {
diff --git a/src/mathicgb/stdinc.h b/src/mathicgb/stdinc.h
index 39ce87f..ef087a6 100755
--- a/src/mathicgb/stdinc.h
+++ b/src/mathicgb/stdinc.h
@@ -3,18 +3,51 @@
#endif
#define MATHICGB_STDINC_GUARD
-#ifdef PROFILE
-#define NO_PINLINE NO_INLINE
-#else
-#define NO_PINLINE
-#endif
+#ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++.
+
+// Sometimes you know that a function will be called very rarely so you want to
+// tell the compiler not to inline it even if it could be inlined at only a
+// modest increase in code size. That is what MATHICGB_NO_INLINE does.
+#define MATHICGB_NO_INLINE __declspec(noinline)
+
+// Sometimes the compiler just will not inline functions that should
+// be inlined. Use sparingly --- preferably only if a profiler says
+// that a tiny often-called function consumes a significant amount of time.
+#define MATHICGB_INLINE __forceinline
+
+// Tells the compiler to always assume that the expression X is true.
+#define MATHICGB_ASSUME(X) __assume(X)
+
+// As MATHICGB_ASSUME, but might actually evaluate X at run-time if it has
+// side-effects. The point is that this can be used on compilers with no other
+// support for assuming things. So there is no difference on MS VC++.
+#define MATHICGB_ASSUME_AND_MAY_EVALUATE(X) __assume(X)
+
+// Tells the compiler that this function returns a pointer that is not an alias
+// for any other point that is currently valid in the program - like malloc.
+#define MATHICGB_RETURN_NO_ALIAS __declspec(restrict)
+
+// Tells the compiler that this function will never throw an exception.
+#define MATHICGB_NOTHROW __declspec(nothrow)
+
+// Tells the compiler that this function has no effects except the return value
+// and the return value depends only on the arguments and first-level
+// indirections of the arguments. (this is the common denominator of GCC
+// and MS VC++ capabilities)
+#define MATHICGB_PURE __declspec(noalias)
+
+// Tells the compiler that the return value of this function must be looked
+// at by the caller. For example this is appropriate for realloc.
+#define MATHICGB_MUST_CHECK_RETURN_VALUE
+
+// Tells the compiler that the current line of code cannot be reached.
+#define MATHICGB_UNREACHABLE __assume(false)
+
+// Tells the compiler that a variable that is a pointer (not a reference)
+// does not alias any other pointer that is used in the current scope.
+#define MATHICGB_RESTRICT __restrict
-#ifndef _MSC_VER
-#define NO_INLINE __attribute__ ((noinline))
-#endif
-#ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++.
-#define NO_INLINE __declspec(noinline)
#pragma warning (disable: 4996) // std::copy on pointers is flagged as dangerous
#pragma warning (disable: 4290) // VC++ ignores throw () specification.
#pragma warning (disable: 4127) // Warns about using "while (true)".
@@ -22,12 +55,36 @@
#pragma warning (disable: 4800) // Warns on int to bool conversion.
#pragma warning (disable: 4146) // Warns on unary minus on unsigned (bit trick)
-
// This warning warns about using the this pointer in base member
// initializer lists. This is a pretty good warning as that can
// obviously easily go wrong, but it is pretty useful to do as well,
// so the warning is turned off.
#pragma warning (disable: 4355)
+
+#elif defined (__GNUC__) // GCC compiler
+
+#define MATHICGB_NO_INLINE __attribute__((noinline))
+#define MATHICGB_INLINE __attribute__((always_inline)) inline
+#define MATHICGB_ASSUME(X)
+#define MATHICGB_ASSUME_AND_MAY_EVALUATE(X) do {if(!(X)){MATHICGB_UNREACHABLE;}while(0)}
+#define MATHICGB_RETURN_NO_ALIAS __attribute__(malloc)
+#define MATHICGB_NOTHROW __attribute__(nothrow)
+#define MATHICGB_PURE __attribute__(pure)
+#define MATHICGB_MUST_CHECK_RETURN_VALUE __attribute__(warn_unused_result)
+#define MATHICGB_UNREACHABLE __builtin_unreachable()
+
+#else
+
+#define MATHICGB_NO_INLINE
+#define MATHICGB_INLINE inline
+#define MATHICGB_ASSUME(X)
+#define MATHICGB_ASSUME_AND_MAY_EVALUATE(X)
+#define MATHICGB_RETURN_NO_ALIAS
+#define MATHICGB_NOTHROW
+#define MATHICGB_PURE
+#define MATHICGB_MUST_CHECK_RETURN_VALUE
+#define MATHICGB_UNREACHABLE
+
#endif
#include <cstddef>
@@ -40,15 +97,17 @@
#define DEBUG
#include <iostream> // Useful for debugging.
#include <cassert>
-#define ASSERT(X) assert(X);
-#define IF_DEBUG(X) X
+#define MATHICGB_ASSERT(X) do{assert(X);}while(0)
+#define MATHICGB_ASSERT_NO_ASSUME(X) MATHICGB_ASSERT(X)
+#define MATHICGB_IF_DEBUG(X) X
#else
-#define ASSERT(X)
-#define IF_DEBUG(X)
+#define MATHICGB_ASSERT(X) MATHICGB_ASSUME(X)
+#define MATHICGB_ASSERT_NO_ASSUME(X)
+#define MATHICGB_IF_DEBUG(X)
#endif
// todo: eventually move all ASSERTs to MATHICGB_ASSERTs and then remove
// ASSERT.
-#define MATHICGB_ASSERT(X) ASSERT(X)
+#define ASSERT(X) MATHICGB_ASSERT(X)
#ifdef MATHICGB_SLOW_DEBUG
// for asserts that take a long time.
diff --git a/src/test/FreeModuleOrderTest.cpp b/src/test/FreeModuleOrderTest.cpp
index 9984db7..e7a1ea3 100755
--- a/src/test/FreeModuleOrderTest.cpp
+++ b/src/test/FreeModuleOrderTest.cpp
@@ -36,12 +36,12 @@ void runTest(
std::istringstream in(correctStr);
for (size_t i = 0; i < answer.size(); ++i) {
in >> answer[i];
- ASSERT(in);
+ MATHICGB_ASSERT(!!in);
}
}
- ASSERT(sigs.size() == pairs.size());
- ASSERT(sigs.size() == pairs.size());
+ MATHICGB_ASSERT(sigs.size() == pairs.size());
+ MATHICGB_ASSERT(sigs.size() == pairs.size());
std::unique_ptr<FreeModuleOrder> order
(FreeModuleOrder::makeOrder(orderType, ideal.get()));
--
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