[mathicgb] 202/393: Added a PrimeField class along with tests. This class is supposed to take over the coefficient code in PolyRing.

Doug Torrance dtorrance-guest at moszumanska.debian.org
Fri Apr 3 15:59:00 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 f86a4b2287fa2b896563ecb5cdde98910c705d27
Author: Bjarke Hammersholt Roune <bjarkehr.code at gmail.com>
Date:   Fri Mar 22 21:53:24 2013 +0100

    Added a PrimeField class along with tests. This class is supposed to take over the coefficient code in PolyRing.
---
 Makefile.am                                        | 104 +++++------
 build/vs12/mathicgb-lib/mathicgb-lib.vcxproj       |   2 +
 .../vs12/mathicgb-lib/mathicgb-lib.vcxproj.filters |   6 +
 build/vs12/mathicgb-test/mathicgb-test.vcxproj     |   1 +
 .../mathicgb-test/mathicgb-test.vcxproj.filters    |   3 +
 src/mathicgb/PrimeField.hpp                        | 199 +++++++++++++++++++++
 src/test/PrimeField.cpp                            | 173 ++++++++++++++++++
 7 files changed, 436 insertions(+), 52 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index f3f66ca..1b8e407 100755
--- a/Makefile.am
+++ b/Makefile.am
@@ -17,58 +17,58 @@ libmathicgb_la_LIBADD= $(DEPS_LIBS)
 
 # the sources that are built to make libmathicgb. Listing the headers in
 # sources ensure that those files are included in distributions.
-libmathicgb_la_SOURCES = src/mathicgb/BjarkeGeobucket2.cpp		\
+libmathicgb_la_SOURCES = src/mathicgb/BjarkeGeobucket2.cpp				\
   src/mathicgb/BjarkeGeobucket2.hpp src/mathicgb/BjarkeGeobucket.cpp	\
-  src/mathicgb/BjarkeGeobucket.hpp src/mathicgb/BuchbergerAlg.cpp	\
-  src/mathicgb/BuchbergerAlg.hpp src/mathicgb/ChainedHashTable.cpp	\
-  src/mathicgb/ChainedHashTable.hpp src/mathicgb/DivisorLookup.hpp	\
-  src/mathicgb/DivisorLookup.cpp src/mathicgb/DivLookup.hpp		\
-  src/mathicgb/FreeModuleOrder.cpp src/mathicgb/FreeModuleOrder.hpp	\
-  src/mathicgb/GroebnerBasis.cpp src/mathicgb/GroebnerBasis.hpp	\
-  src/mathicgb/HashTourReducer.cpp src/mathicgb/HashTourReducer.hpp	\
-  src/mathicgb/Ideal.cpp src/mathicgb/Ideal.hpp			\
-  src/mathicgb/io-util.cpp src/mathicgb/io-util.hpp			\
-  src/mathicgb/KoszulQueue.cpp src/mathicgb/KoszulQueue.hpp		\
-  src/mathicgb/MonomialHashTable.hpp					\
-  src/mathicgb/MonTableDivList.hpp src/mathicgb/MonTableKDTree.hpp	\
-  src/mathicgb/MonTableNaive.cpp src/mathicgb/MonTableNaive.hpp		\
-  src/mathicgb/MTArray.cpp src/mathicgb/MTArray.hpp			\
-  src/mathicgb/PairTriangle.cpp src/mathicgb/PairTriangle.hpp		\
-  src/mathicgb/Poly.cpp src/mathicgb/Poly.hpp				\
-  src/mathicgb/PolyBasis.cpp src/mathicgb/PolyBasis.hpp			\
-  src/mathicgb/PolyGeoBucket.cpp src/mathicgb/PolyGeoBucket.hpp		\
-  src/mathicgb/PolyHashReducer.cpp src/mathicgb/PolyHashReducer.hpp	\
-  src/mathicgb/PolyHashTable.cpp src/mathicgb/PolyHashTable.hpp		\
-  src/mathicgb/PolyHeap.cpp src/mathicgb/PolyHeap.hpp			\
-  src/mathicgb/PolyReducer.cpp src/mathicgb/PolyReducer.hpp		\
-  src/mathicgb/PolyRing.cpp src/mathicgb/PolyRing.hpp			\
-  src/mathicgb/Reducer.cpp src/mathicgb/Reducer.hpp			\
-  src/mathicgb/ReducerDedup.hpp src/mathicgb/ReducerHash.hpp		\
-  src/mathicgb/ReducerHashPack.hpp src/mathicgb/ReducerHelper.hpp	\
-  src/mathicgb/ReducerNoDedup.hpp src/mathicgb/ReducerPack.hpp		\
-  src/mathicgb/ReducerPackDedup.hpp src/mathicgb/SignatureGB.cpp	\
-  src/mathicgb/SignatureGB.hpp src/mathicgb/SigSPairs.cpp		\
-  src/mathicgb/SigSPairs.hpp src/mathicgb/SPairs.cpp			\
-  src/mathicgb/SPairs.hpp 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/QuadMatrixBuilder.hpp	\
-  src/mathicgb/QuadMatrixBuilder.cpp src/mathicgb/TypicalReducer.cpp\
-  src/mathicgb/TypicalReducer.cpp src/mathicgb/F4Reducer.hpp		\
-  src/mathicgb/F4Reducer.cpp src/mathicgb/F4MatrixBuilder.hpp		\
-  src/mathicgb/F4MatrixBuilder.cpp src/mathicgb/QuadMatrix.hpp		\
-  src/mathicgb/QuadMatrix.cpp src/mathicgb/F4MatrixReducer.cpp		\
-  src/mathicgb/F4MatrixReducer.hpp src/mathicgb/MonomialMap.hpp	\
-  src/mathicgb/RawVector.hpp src/mathicgb/Atomic.hpp			\
-  src/mathicgb/FixedSizeMonomialMap.hpp src/mathicgb/CFile.hpp		\
-  src/mathicgb/CFile.cpp src/mathicgb/LogDomain.hpp			\
-  src/mathicgb/LogDomain.cpp src/mathicgb/LogDomainSet.hpp \
-  src/mathicgb/F4MatrixBuilder2.hpp src/mathicgb/F4MatrixBuilder2.cpp \
-  src/mathicgb/LogDomainSet.cpp src/mathicgb/F4ProtoMatrix.hpp \
-  src/mathicgb/F4ProtoMatrix.cpp src/mathicgb/F4MatrixProject.hpp \
-  src/mathicgb/F4MatrixProjection.cpp src/mathicgb/ScopeExit.hpp \
-  src/mathicgb.cpp src/mathicgb.h src/mathicgb/mtbb.hpp
+  src/mathicgb/BjarkeGeobucket.hpp src/mathicgb/BuchbergerAlg.cpp		\
+  src/mathicgb/BuchbergerAlg.hpp src/mathicgb/ChainedHashTable.cpp		\
+  src/mathicgb/ChainedHashTable.hpp src/mathicgb/DivisorLookup.hpp		\
+  src/mathicgb/DivisorLookup.cpp src/mathicgb/DivLookup.hpp				\
+  src/mathicgb/FreeModuleOrder.cpp src/mathicgb/FreeModuleOrder.hpp		\
+  src/mathicgb/GroebnerBasis.cpp src/mathicgb/GroebnerBasis.hpp			\
+  src/mathicgb/HashTourReducer.cpp src/mathicgb/HashTourReducer.hpp		\
+  src/mathicgb/Ideal.cpp src/mathicgb/Ideal.hpp							\
+  src/mathicgb/io-util.cpp src/mathicgb/io-util.hpp						\
+  src/mathicgb/KoszulQueue.cpp src/mathicgb/KoszulQueue.hpp				\
+  src/mathicgb/MonomialHashTable.hpp src/mathicgb/MonTableDivList.hpp	\
+  src/mathicgb/MonTableKDTree.hpp src/mathicgb/MonTableNaive.cpp		\
+  src/mathicgb/MonTableNaive.hpp src/mathicgb/MTArray.cpp				\
+  src/mathicgb/MTArray.hpp src/mathicgb/PairTriangle.cpp				\
+  src/mathicgb/PairTriangle.hpp src/mathicgb/Poly.cpp					\
+  src/mathicgb/Poly.hpp src/mathicgb/PolyBasis.cpp						\
+  src/mathicgb/PolyBasis.hpp src/mathicgb/PolyGeoBucket.cpp				\
+  src/mathicgb/PolyGeoBucket.hpp src/mathicgb/PolyHashReducer.cpp		\
+  src/mathicgb/PolyHashReducer.hpp src/mathicgb/PolyHashTable.cpp		\
+  src/mathicgb/PolyHashTable.hpp src/mathicgb/PolyHeap.cpp				\
+  src/mathicgb/PolyHeap.hpp src/mathicgb/PolyReducer.cpp				\
+  src/mathicgb/PolyReducer.hpp src/mathicgb/PolyRing.cpp				\
+  src/mathicgb/PolyRing.hpp src/mathicgb/Reducer.cpp					\
+  src/mathicgb/Reducer.hpp src/mathicgb/ReducerDedup.hpp				\
+  src/mathicgb/ReducerHash.hpp src/mathicgb/ReducerHashPack.hpp			\
+  src/mathicgb/ReducerHelper.hpp src/mathicgb/ReducerNoDedup.hpp		\
+  src/mathicgb/ReducerPack.hpp src/mathicgb/ReducerPackDedup.hpp		\
+  src/mathicgb/SignatureGB.cpp src/mathicgb/SignatureGB.hpp				\
+  src/mathicgb/SigSPairs.cpp src/mathicgb/SigSPairs.hpp					\
+  src/mathicgb/SPairs.cpp src/mathicgb/SPairs.hpp						\
+  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/QuadMatrixBuilder.hpp		\
+  src/mathicgb/QuadMatrixBuilder.cpp src/mathicgb/TypicalReducer.cpp	\
+  src/mathicgb/TypicalReducer.cpp src/mathicgb/F4Reducer.hpp			\
+  src/mathicgb/F4Reducer.cpp src/mathicgb/F4MatrixBuilder.hpp			\
+  src/mathicgb/F4MatrixBuilder.cpp src/mathicgb/QuadMatrix.hpp			\
+  src/mathicgb/QuadMatrix.cpp src/mathicgb/F4MatrixReducer.cpp			\
+  src/mathicgb/F4MatrixReducer.hpp src/mathicgb/MonomialMap.hpp			\
+  src/mathicgb/RawVector.hpp src/mathicgb/Atomic.hpp					\
+  src/mathicgb/FixedSizeMonomialMap.hpp src/mathicgb/CFile.hpp			\
+  src/mathicgb/CFile.cpp src/mathicgb/LogDomain.hpp						\
+  src/mathicgb/LogDomain.cpp src/mathicgb/LogDomainSet.hpp				\
+  src/mathicgb/F4MatrixBuilder2.hpp src/mathicgb/F4MatrixBuilder2.cpp	\
+  src/mathicgb/LogDomainSet.cpp src/mathicgb/F4ProtoMatrix.hpp			\
+  src/mathicgb/F4ProtoMatrix.cpp src/mathicgb/F4MatrixProject.hpp		\
+  src/mathicgb/F4MatrixProjection.cpp src/mathicgb/ScopeExit.hpp		\
+  src/mathicgb.cpp src/mathicgb.h src/mathicgb/mtbb.hpp					\
+  src/mathicgb/PrimeField.hpp src/mathicgb/PrimeField.cpp
 
 
 # The headers that libmathicgb installs.
@@ -115,7 +115,7 @@ unittest_SOURCES=src/test/FreeModuleOrderTest.cpp						\
   src/test/ideals.cpp src/test/poly-test.cpp src/test/ideals.hpp		\
   src/test/SparseMatrix.cpp src/test/QuadMatrixBuilder.cpp				\
   src/test/F4MatrixBuilder.cpp src/test/F4MatrixReducer.cpp             \
-  src/test/mathicgb.cpp
+  src/test/mathicgb.cpp src/test/PrimeField.cpp
 
 else
 
diff --git a/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj b/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj
index 6a59c49..64901bf 100755
--- a/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj
+++ b/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj
@@ -471,6 +471,7 @@
     <ClCompile Include="..\..\..\src\mathicgb\PolyHeap.cpp" />
     <ClCompile Include="..\..\..\src\mathicgb\PolyReducer.cpp" />
     <ClCompile Include="..\..\..\src\mathicgb\PolyRing.cpp" />
+    <ClCompile Include="..\..\..\src\mathicgb\PrimeField.cpp" />
     <ClCompile Include="..\..\..\src\mathicgb\QuadMatrix.cpp" />
     <ClCompile Include="..\..\..\src\mathicgb\QuadMatrixBuilder.cpp" />
     <ClCompile Include="..\..\..\src\mathicgb\Reducer.cpp" />
@@ -523,6 +524,7 @@
     <ClInclude Include="..\..\..\src\mathicgb\PolyHeap.hpp" />
     <ClInclude Include="..\..\..\src\mathicgb\PolyReducer.hpp" />
     <ClInclude Include="..\..\..\src\mathicgb\PolyRing.hpp" />
+    <ClInclude Include="..\..\..\src\mathicgb\PrimeField.hpp" />
     <ClInclude Include="..\..\..\src\mathicgb\QuadMatrix.hpp" />
     <ClInclude Include="..\..\..\src\mathicgb\QuadMatrixBuilder.hpp" />
     <ClInclude Include="..\..\..\src\mathicgb\RawVector.hpp" />
diff --git a/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj.filters b/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj.filters
index 7b57653..608440b 100755
--- a/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj.filters
+++ b/build/vs12/mathicgb-lib/mathicgb-lib.vcxproj.filters
@@ -141,6 +141,9 @@
     <ClCompile Include="..\..\..\src\mathicgb.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\..\src\mathicgb\PrimeField.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\..\src\mathicgb\BjarkeGeobucket.hpp">
@@ -323,5 +326,8 @@
     <ClInclude Include="..\..\..\src\mathicgb\mtbb.hpp">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\..\src\mathicgb\PrimeField.hpp">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/build/vs12/mathicgb-test/mathicgb-test.vcxproj b/build/vs12/mathicgb-test/mathicgb-test.vcxproj
index 6c53744..3289285 100755
--- a/build/vs12/mathicgb-test/mathicgb-test.vcxproj
+++ b/build/vs12/mathicgb-test/mathicgb-test.vcxproj
@@ -404,6 +404,7 @@
     <ClCompile Include="..\..\..\src\test\ideals.cpp" />
     <ClCompile Include="..\..\..\src\test\mathicgb.cpp" />
     <ClCompile Include="..\..\..\src\test\poly-test.cpp" />
+    <ClCompile Include="..\..\..\src\test\PrimeField.cpp" />
     <ClCompile Include="..\..\..\src\test\QuadMatrixBuilder.cpp" />
     <ClCompile Include="..\..\..\src\test\SparseMatrix.cpp" />
     <ClCompile Include="..\..\..\src\test\testMain.cpp" />
diff --git a/build/vs12/mathicgb-test/mathicgb-test.vcxproj.filters b/build/vs12/mathicgb-test/mathicgb-test.vcxproj.filters
index eb741c1..d84330d 100755
--- a/build/vs12/mathicgb-test/mathicgb-test.vcxproj.filters
+++ b/build/vs12/mathicgb-test/mathicgb-test.vcxproj.filters
@@ -48,6 +48,9 @@
     <ClCompile Include="..\..\..\src\test\mathicgb.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\..\src\test\PrimeField.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\..\src\test\ideals.hpp">
diff --git a/src/mathicgb/PrimeField.hpp b/src/mathicgb/PrimeField.hpp
new file mode 100644
index 0000000..7a90c54
--- /dev/null
+++ b/src/mathicgb/PrimeField.hpp
@@ -0,0 +1,199 @@
+#ifndef MATHICGB_PRIME_FIELD_GUARD
+#define MATHICGB_PRIME_FIELD_GUARD
+
+#include <limits>
+#include <type_traits>
+#include <ostream>
+
+/// Implements arithmetic in a prime field. T must be an unsigned integer type
+/// that is used to store the elements of the field. The characteristic of the
+/// field must be a prime not exceeding std::numeric_limits<T>::max().
+template<class T>
+class PrimeField {
+public:
+  class Element {
+  public:
+    static_assert(!std::numeric_limits<T>::is_signed, "");
+    static_assert(std::numeric_limits<T>::is_integer, "");
+
+    Element(const Element& e): mValue(e.value()) {}
+
+    Element& operator=(const Element& e) {
+      mValue = e.value();
+      return *this;
+    }
+
+    bool operator==(const Element e) const {return value() == e.value();}
+    bool operator!=(const Element e) const {return !(*this == e);}
+    T value() const {return mValue;}
+
+  private:
+    friend class PrimeField;
+    Element(const T value): mValue(value) {}
+
+    friend class PrimeFile;
+    T mValue;
+  };
+
+  PrimeField(const T primeCharacteristic): mCharac(primeCharacteristic) {}
+
+  Element zero() const {return Element(0);}
+  Element one() const {return Element(1);}
+
+  bool isZero(const Element a) const {return a == zero();}
+  bool isOne(const Element a) const {return a == one();}
+
+  T charac() const {return mCharac;}
+
+  template<class Integer>
+  Element toElement(Integer&& i) const {
+    typedef typename std::remove_reference<Integer>::type NoRefInteger;
+    static_assert(std::numeric_limits<NoRefInteger>::is_integer, "");
+
+    // We need to take the modulus of i to put it into the range [0;charac()).
+    // That is more tricky to get right than it might seem.
+    //
+    // The sign of a % b is implementation defined in C++ if either of a or b
+    // are negative. We need the positive remainder so the operands have to be
+    // positive. Another reason for this is that we could not allow b to be
+    // converted to a signed integer since it might not be representable that
+    // way.
+    //
+    // If Integer is signed and i is std::numeric_limits<Integer>::min() then
+    // it is undefined behavior to evaluate the expression -i since -i is not
+    // representable, leading to a signed overflow. So we have to cast to
+    // unsigned before doing the minus.
+    typedef typename std::make_unsigned<NoRefInteger>::type Unsigned;
+    if (i < 0) {
+      // Negate i to get a positive number, then negate again to cancel out
+      // the first negation. The first cast to unsigned is to avoid
+      // undefined behavior from -i. The second is there because apparently,
+      // at least on GCC, the unary - re-introduces signed and we need to
+      // be unsigned to avoid sign extension. We need zero extension.
+      const auto unsignedNegative =
+        static_cast<Unsigned>(-static_cast<Unsigned>(i));
+      return negative(Element(unsignedNegative % charac()));
+    } else
+      return Element(static_cast<Unsigned>(i) % charac());
+  }
+
+  T toValue(Element e) const {return e.value;}
+
+  Element sum(const Element a, const Element b) const {
+    const auto s = a.value() + b.value();
+    // The sum overflowed if and only if a.value() > s. In that case
+    // subtraction of charac() will overflow again in the other direction,
+    // leaving us with the correct result.
+    if (a.value() > s || s >= charac()) {
+      MATHICGB_ASSERT(s - charac() < charac());
+      return Element(s - charac());
+    } else
+      return Element(s);
+  }
+
+  Element difference(const Element a, const Element b) const {
+    if (a.value() < b.value()) {
+      MATHICGB_ASSERT(a.value() - b.value() + charac() < charac());
+      return Element(a.value() - b.value() + charac());
+    } else
+      return Element(a.value() - b.value());
+  }
+
+  Element negative(const Element a) const {
+    if (a.value() == 0)
+      return a;
+    else
+      return negativeNonZero(a);
+  }
+
+  Element negativeNonZero(const Element a) const {
+    MATHICGB_ASSERT(!isZero(a));
+    return Element(charac() - a.value());
+  }
+
+  Element product(const Element a, const Element b) const;
+
+  /// Returns the multiplicative inverse a^-1 mod charac(). a must not be zero.
+  Element inverse(const Element a) const;
+
+private:
+  const T mCharac;
+};
+
+namespace PrimeFieldInternal {
+  template<class T>
+  struct ModularProdType {};
+  template<> struct ModularProdType<uint8> {typedef uint16 type;};
+  template<> struct ModularProdType<uint16> {typedef uint32 type;};
+  template<> struct ModularProdType<uint32> {typedef uint64 type;};
+}
+
+template<class T>
+auto PrimeField<T>::product(
+  const Element a,
+  const Element b
+) const -> Element {
+  typedef typename PrimeFieldInternal::ModularProdType<T>::type BigT;
+  BigT bigProd = static_cast<BigT>(a.value()) * b.value();
+  MATHICGB_ASSERT(a.value() == 0 || bigProd / a.value() == b.value());
+  return Element(static_cast<T>(bigProd % charac()));
+}
+
+template<class T>
+auto PrimeField<T>::inverse(const Element elementA) const -> Element {
+  // We do two turns of the extended Euclidian algorithm per
+  // loop. Usually the sign of x changes each time through the loop,
+  // but we avoid that by representing every other x as its negative,
+  // which is the value minusLastX. This way no negative values ever
+  // appear and we do not need any extra bits.
+
+  auto a = elementA.value();
+  MATHICGB_ASSERT(0 < a);
+  MATHICGB_ASSERT(a < charac());
+#ifdef MATHICGB_DEBUG
+  const auto origA = a;
+#endif
+  auto b = charac();
+  auto minusLastX = static_cast<T>(0);
+  auto x = static_cast<T>(1);
+  while (true) {
+    MATHICGB_ASSERT(x <= charac());
+    MATHICGB_ASSERT(minusLastX <= charac());
+
+    // first turn
+    if (a == 1)
+      break;
+    const auto firstQuotient = b / a;
+    b -= firstQuotient * a;
+    minusLastX += firstQuotient * x;
+
+    // second turn
+    if (b == 1) {
+      MATHICGB_ASSERT(minusLastX != 0);
+      MATHICGB_ASSERT(minusLastX < charac());
+      x = charac() - minusLastX;
+      break;
+    }
+    const auto secondQuotient = a / b;
+    a -= secondQuotient * b;
+    x += secondQuotient * minusLastX;
+  }
+  MATHICGB_ASSERT(x >= 1);
+  MATHICGB_ASSERT(x < charac());
+
+  const  Element inverseElement(x);
+  MATHICGB_ASSERT(isOne(product(elementA, inverseElement)));
+  return inverseElement;
+}
+
+
+template<class T>
+std::ostream& operator<<(
+  std::ostream& out,
+  typename PrimeField<T>::Element e
+) {
+  out << e.value();
+  return out;
+}
+
+#endif
diff --git a/src/test/PrimeField.cpp b/src/test/PrimeField.cpp
new file mode 100644
index 0000000..9221c9e
--- /dev/null
+++ b/src/test/PrimeField.cpp
@@ -0,0 +1,173 @@
+#include "mathicgb/stdinc.h"
+
+#include "mathicgb/PrimeField.hpp"
+#include <gtest/gtest.h>
+#include <sstream>
+
+namespace {
+  template<class T>
+  std::string toString(T&& t) {
+    std::ostringstream out;
+    out << static_cast<uint64>(t.value());
+    return out.str();
+  }
+}
+
+TEST(PrimeField, Charac) {
+  const PrimeField<unsigned char> pf(11);
+  ASSERT_EQ(pf.charac(), 11);
+}
+
+TEST(PrimeField, OneZero) {
+  const PrimeField<unsigned char> pfChar(11);
+  ASSERT_EQ("0", toString(pfChar.zero()));
+  ASSERT_EQ("1", toString(pfChar.one()));
+  ASSERT_TRUE(pfChar.isOne(pfChar.one()));
+  ASSERT_FALSE(pfChar.isOne(pfChar.zero()));
+  ASSERT_FALSE(pfChar.isZero(pfChar.one()));
+  ASSERT_TRUE(pfChar.isZero(pfChar.zero()));
+
+  const PrimeField<unsigned long> pfLong(11);
+  ASSERT_EQ("0", toString(pfLong.zero()));
+  ASSERT_EQ("1", toString(pfLong.one()));
+  ASSERT_TRUE(pfLong.isOne(pfLong.one()));
+  ASSERT_FALSE(pfLong.isOne(pfLong.zero()));
+  ASSERT_FALSE(pfLong.isZero(pfLong.one()));
+  ASSERT_TRUE(pfLong.isZero(pfLong.zero()));
+}
+
+TEST(PrimeField, toElement) {
+  const auto max32BitUnsignedPrime = 4294967291u;
+  const PrimeField<unsigned int> pf(max32BitUnsignedPrime);
+
+  // Same number of bits (32)
+  ASSERT_EQ("0", toString(pf.toElement(0)));
+  ASSERT_EQ("1", toString(pf.toElement(1)));
+  ASSERT_EQ("4294967290", toString(pf.toElement(-1)));
+
+  ASSERT_EQ("0", toString(pf.toElement(max32BitUnsignedPrime)));
+  ASSERT_EQ("1", toString(pf.toElement(max32BitUnsignedPrime + 1u)));
+  ASSERT_EQ("4294967290", toString(pf.toElement(max32BitUnsignedPrime - 1u)));
+
+  ASSERT_EQ("4",
+    toString(pf.toElement(std::numeric_limits<unsigned int>::max())));
+  ASSERT_EQ("2147483643",
+    toString(pf.toElement(std::numeric_limits<int>::min())));
+
+  // Fewer number of bits (8)
+  ASSERT_EQ("127", toString(pf.toElement(std::numeric_limits<char>::max())));
+  ASSERT_EQ("4294967163",
+    toString(pf.toElement(std::numeric_limits<char>::min())));
+
+  ASSERT_EQ("255",
+    toString(pf.toElement(std::numeric_limits<unsigned char>::max())));
+  ASSERT_EQ("0",
+    toString(pf.toElement(std::numeric_limits<unsigned char>::min())));
+
+  // More bits (64)
+  ASSERT_EQ("24", toString(pf.toElement(std::numeric_limits<uint64>::max())));
+  ASSERT_EQ("2147483657",
+    toString(pf.toElement(std::numeric_limits<int64>::max())));
+  ASSERT_EQ("2147483633",
+    toString(pf.toElement(std::numeric_limits<int64>::min())));
+}
+
+TEST(PrimeField, Sum) {
+  const PrimeField<unsigned char> pf2(2);
+  ASSERT_EQ(pf2.zero(), pf2.sum(pf2.zero(), pf2.zero()));
+  ASSERT_EQ(pf2.one(), pf2.sum(pf2.one(), pf2.zero()));
+  ASSERT_EQ(pf2.one(), pf2.sum(pf2.zero(), pf2.one()));
+  ASSERT_EQ(pf2.zero(), pf2.sum(pf2.one(), pf2.one()));
+
+  const PrimeField<unsigned char> pf251(251);
+  ASSERT_EQ(pf251.one(), pf251.sum(pf251.zero(), pf251.one()));
+  ASSERT_EQ(pf251.toElement(-3),
+    pf251.sum(pf251.toElement(-1), pf251.toElement(-2)));
+
+  const PrimeField<unsigned char> pf101(101);
+  ASSERT_EQ(pf101.toElement(100),
+    pf101.sum(pf101.toElement(40), pf101.toElement(60)));
+  ASSERT_EQ(pf101.toElement(9),
+    pf101.sum(pf101.toElement(50), pf101.toElement(60)));
+}
+
+TEST(PrimeField, Negative) {
+  const PrimeField<unsigned char> pf2(2);
+  ASSERT_EQ(pf2.zero(), pf2.negative(pf2.zero()));
+  ASSERT_EQ(pf2.one(), pf2.negative(pf2.one()));
+  ASSERT_EQ(pf2.one(), pf2.negativeNonZero(pf2.one()));
+
+  const PrimeField<unsigned char> pf251(251);
+  ASSERT_EQ(pf251.zero(), pf251.negative(pf251.zero()));
+  ASSERT_EQ(pf251.toElement(100), pf251.negative(pf251.toElement(151)));
+  ASSERT_EQ(pf251.toElement(100), pf251.negativeNonZero(pf251.toElement(151)));
+}
+
+TEST(PrimeField, Difference) {
+  const PrimeField<unsigned char> pf2(2);
+  ASSERT_EQ(pf2.zero(), pf2.difference(pf2.zero(), pf2.zero()));
+  ASSERT_EQ(pf2.one(), pf2.difference(pf2.one(), pf2.zero()));
+  ASSERT_EQ(pf2.one(), pf2.difference(pf2.zero(), pf2.one()));
+  ASSERT_EQ(pf2.zero(), pf2.difference(pf2.one(), pf2.one()));
+
+  const PrimeField<unsigned char> pf251(251);
+  ASSERT_EQ(pf251.one(), pf251.difference(pf251.one(), pf251.zero()));
+  ASSERT_EQ(pf251.toElement(-3),
+    pf251.difference(pf251.toElement(1), pf251.toElement(4)));
+
+  const PrimeField<unsigned char> pf101(101);
+  ASSERT_EQ(pf101.toElement(20),
+    pf101.difference(pf101.toElement(60), pf101.toElement(40)));
+  ASSERT_EQ(pf101.toElement(-20),
+    pf101.difference(pf101.toElement(40), pf101.toElement(60)));
+}
+
+TEST(PrimeField, Product) {
+  const PrimeField<unsigned char> pf2(2);
+  ASSERT_EQ(pf2.zero(), pf2.product(pf2.zero(), pf2.zero()));
+  ASSERT_EQ(pf2.zero(), pf2.product(pf2.one(), pf2.zero()));
+  ASSERT_EQ(pf2.zero(), pf2.product(pf2.zero(), pf2.one()));
+  ASSERT_EQ(pf2.one(), pf2.product(pf2.one(), pf2.one()));
+
+  const PrimeField<unsigned char> pf251(251);
+  ASSERT_EQ(pf251.zero(), pf251.product(pf251.one(), pf251.zero()));
+  ASSERT_EQ(pf251.one(), pf251.product(pf251.one(), pf251.one()));
+  ASSERT_EQ(pf251.one(), 
+    pf251.product(pf251.toElement(-1), pf251.toElement(-1)));
+  ASSERT_EQ(pf251.one(), 
+    pf251.product(pf251.toElement(2), pf251.toElement(126)));
+
+  const PrimeField<unsigned char> pf101(101);
+  ASSERT_EQ(pf101.toElement(20),
+    pf101.product(pf101.toElement(5), pf101.toElement(4)));
+  ASSERT_EQ(pf101.toElement(-20),
+    pf101.product(pf101.toElement(-2), pf101.toElement(10)));
+
+  const PrimeField<uint16> pf16(65521);
+  ASSERT_EQ(pf16.toElement(-20),
+    pf16.product(pf16.toElement(-2), pf16.toElement(10)));
+
+  const PrimeField<uint32> pf32(4294967291u);
+  ASSERT_EQ(pf32.toElement(-20),
+    pf32.product(pf32.toElement(-2), pf32.toElement(10)));
+}
+
+TEST(PrimeField, Inverse) {
+  const PrimeField<unsigned char> pf2(2);
+  ASSERT_EQ(pf2.one(), pf2.inverse(pf2.one()));
+
+  const PrimeField<unsigned char> pf251(251);
+  ASSERT_EQ(pf251.one(), pf2.inverse(pf251.one()));
+  ASSERT_EQ(pf251.toElement(-1), pf251.inverse(pf251.toElement(-1)));
+  ASSERT_EQ(pf251.toElement(235), pf251.inverse(pf251.toElement(47)));
+
+  const PrimeField<uint16> pf16(65521);
+  ASSERT_EQ(pf16.one(), pf16.inverse(pf16.one()));
+  ASSERT_EQ(pf16.toElement(-1), pf16.inverse(pf16.toElement(-1)));
+  ASSERT_EQ(pf16.toElement(43216), pf16.inverse(pf16.toElement(47)));
+
+  const PrimeField<uint32> pf32(4294967291u);
+  ASSERT_EQ(pf32.one(), pf32.inverse(pf32.one()));
+  ASSERT_EQ(pf32.toElement(-1), pf32.inverse(pf32.toElement(-1)));
+  ASSERT_EQ(pf32.toElement(3015615332u), pf32.inverse(pf32.toElement(47)));
+}

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