[mathicgb] 389/393: Implemented module input algorithm - an early version. It doesn't work with KD trees right now, so you have to select the list data structures. You also have to use the -module parameter. Only works with the classic GB algorithm, though the F4 reducer seems to work (supposing this works at all). No testing has been done yet, so there may well be lots of issues. Also made the header for ClassicGBAlg expose less information.

Doug Torrance dtorrance-guest at moszumanska.debian.org
Fri Apr 3 15:59:38 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 557a3b9982c1ed8a558d7203be902bc88c554980
Author: Bjarke Hammersholt Roune <bjarkehr.code at gmail.com>
Date:   Wed Sep 25 16:58:24 2013 +0200

    Implemented module input algorithm - an early version. It doesn't work with KD trees right now, so you have to select the list data structures. You also have to use the -module parameter. Only works with the classic GB algorithm, though the F4 reducer seems to work (supposing this works at all). No testing has been done yet, so there may well be lots of issues. Also made the header for ClassicGBAlg expose less information.
---
 doc/description.txt            |  37 ++++++++++++
 examples/module.ideal          |   6 ++
 src/cli/GBAction.cpp           |  72 ++++++++++++----------
 src/cli/GBAction.hpp           |   1 +
 src/cli/GBCommonParams.cpp     |  75 ++++++++++++++---------
 src/cli/SigGBAction.cpp        |  35 +++++------
 src/mathicgb.cpp               |  30 ++++++----
 src/mathicgb/ClassicGBAlg.cpp  | 132 +++++++++++++++++++++++++++++++++++++++--
 src/mathicgb/ClassicGBAlg.hpp  | 111 ++++++----------------------------
 src/mathicgb/MonoMonoid.hpp    |  46 +++++++++++++-
 src/mathicgb/Poly.hpp          |   6 ++
 src/mathicgb/PolyBasis.cpp     |   2 +-
 src/mathicgb/SPairs.cpp        |  21 +++++--
 src/mathicgb/SPairs.hpp        |   2 -
 src/mathicgb/StaticMonoMap.hpp |   8 +--
 src/test/gb-test.cpp           |  40 ++++++++-----
 16 files changed, 412 insertions(+), 212 deletions(-)

diff --git a/doc/description.txt b/doc/description.txt
index 2490beb..7b4ee01 100755
--- a/doc/description.txt
+++ b/doc/description.txt
@@ -1121,6 +1121,16 @@ capitalized. First letter of functions and variables is
 lowerCase. Member variables are prefixed with an m, so
 mMyMemberVariable.
 
+Project(low-effort, low-difficulty): Describe the coding style more
+clearly and in more detail.
+
+Project(medium-effort, low-difficulty): Not all of MathicGB code
+entirely follows this coding style. Reformat that code.
+
+Project(medium-effort, medium-difficulty): Set up an automatic coding
+style checker to check the coding style.
+
+
 -- exceptions
 
 Exceptions are used to signal errors. Code should be exception safe at
@@ -2320,3 +2330,30 @@ everyone to know about it. Attract more developers.
 
 Project (high-effort, medium-difficulty): Write a nice user's manual.
 
+Project (medium-effort, medium-difficulty): There are currently no
+tests that directly invoke the command line interface. Set some up.
+
+Project (medium-effort, medium-difficulty): Reducer is a virtual
+interface and it's intended to be used via unique_ptr handles. Not too
+bad, but value semantics would be nicer. Try this sort of technique out:
+
+  http://channel9.msdn.com/Events/GoingNative/2013/Inheritance-Is-The-Base-Class-of-Evil
+
+The idea here is to push the virtualness inside the class so that it
+becomes an implementation detail instead of something that is exposed
+to clients of the class. Exactly how this should be done for Reducer,
+evaluating if this is even a good idea and figuring out if this idea
+should be applied to widely to other instances of polymorphism in
+MathicGB is part of the project.
+
+Project (medium-effort, medium-difficulty): MathicGB was first written
+before C++11. So to move data around without copying, we used
+std::auto_ptr. Once we started using C++11, all of those were then
+replaced with std::unique_ptr. However, for classes with move
+semantics, we can now just move them around using those move semantics
+without wrapping things in a std::unique_ptr. It's an unnecessary
+indirection. Find all unnecessary std::unique_ptr's and get rid of
+them. Look for std::unique_ptr<T> where T is a non-virtual class with
+move semantics - that's a good clue that probably std::unique_ptr
+isn't doing anything useful there. The main example of this is
+std::unique_ptr<Poly>, which appears in several places.
diff --git a/examples/module.ideal b/examples/module.ideal
new file mode 100755
index 0000000..94b4bf0
--- /dev/null
+++ b/examples/module.ideal
@@ -0,0 +1,6 @@
+101 4 1 1 1 1 1
+4
+ a<1>+b<2>+c<1>+d<1>
+ ab<1>+bc<1>+cd<1>+da<1>
+ abc<1>+bcd<1>+cda<1>+dab<1>
+ abcd<1>-1<1>
diff --git a/src/cli/GBAction.cpp b/src/cli/GBAction.cpp
index d0b06dc..9f7be4d 100755
--- a/src/cli/GBAction.cpp
+++ b/src/cli/GBAction.cpp
@@ -9,35 +9,47 @@
 #include "mathicgb/F4Reducer.hpp"
 #include "mathicgb/Scanner.hpp"
 #include "mathicgb/MathicIO.hpp"
+#include "mathicgb/Reducer.hpp"
 #include <fstream>
 #include <iostream>
 
 MATHICGB_NAMESPACE_BEGIN
 
 GBAction::GBAction():
-  mAutoTailReduce("autoTailReduce",
+  mAutoTailReduce(
+    "autoTailReduce",
     "Reduce the non-leading terms of all polynomials whenever an element "
     "is inserted into the basis. Only relevant to the "
     "classic Buchberger algorithm.",
     false),
 
-  mAutoTopReduce("autoTopReduce",
+  mAutoTopReduce(
+    "autoTopReduce",
     "Reduce any basis element whose lead term becomes reducible "
     "by a different basis element. Only relevant to the "
     "classic Buchberger algorithm.",
     true),
 
-  mSPairGroupSize("sPairGroupSize",
+  mSPairGroupSize(
+    "sPairGroupSize",
     "Specifies how many S-pair to reduce at one time. A value of 0 "
     "indicates to use an appropriate default.",
     0),
 
- mMinMatrixToStore("storeMatrices",
-   "If using a matrix-based reducer, store the matrices that are generated in "
-   "files named X-1.mat, X-2.mat and so on where X is the project name. Only "
-   "matrices with at least as many entries as the parameter are stored. "
-   "A value of 0 indicates not to store any matrices.",
-   0),
+  mMinMatrixToStore(
+    "storeMatrices",
+    "If using a matrix-based reducer, store the matrices that are generated in "
+    "files named X-1.mat, X-2.mat and so on where X is the project name. Only "
+    "matrices with at least as many entries as the parameter are stored. "
+    "A value of 0 indicates not to store any matrices.",
+    0),
+
+  mModule(
+    "module",
+    "The input is a basis of a submodule over the polynomial ring instead of "
+    "an ideal in the polynomial ring. This option is experimental.",
+    false
+  ),
 
    mParams(1, 1)
 {}
@@ -63,7 +75,7 @@ void GBAction::performAction() {
   Scanner in(inputFile);
   auto p = MathicIO<>().readRing(true, in);
   auto& ring = *p.first;
-  auto basis = MathicIO<>().readBasis(ring, false, in);
+  auto basis = MathicIO<>().readBasis(ring, mModule.value(), in);
 
   // run algorithm
   const auto reducerType = Reducer::reducerType(mGBParams.mReducer.value());
@@ -83,28 +95,26 @@ void GBAction::performAction() {
     reducer = std::move(f4Reducer);
   }
 
-  ClassicGBAlg alg(
-    basis,
-    *reducer,
-    mGBParams.mMonoLookup.value(),
-    mGBParams.mPreferSparseReducers.value(),
-    mGBParams.mSPairQueue.value());
-  alg.setBreakAfter(mGBParams.mBreakAfter.value());
-  alg.setPrintInterval(mGBParams.mPrintInterval.value());
-  alg.setSPairGroupSize(mSPairGroupSize.value());
-  alg.setReducerMemoryQuantum(mGBParams.mMemoryQuantum.value());
-  alg.setUseAutoTopReduction(mAutoTopReduce.value());
-  alg.setUseAutoTailReduction(mAutoTailReduce.value());
-
-  alg.computeGrobnerBasis();
-  alg.printStats(std::cerr);
+  ClassicGBAlgParams params;
+  params.reducer = reducer.get();
+  params.monoLookupType = mGBParams.mMonoLookup.value();
+  params.preferSparseReducers = mGBParams.mPreferSparseReducers.value();
+  params.sPairQueueType = mGBParams.mSPairQueue.value();
+  params.breakAfter = mGBParams.mBreakAfter.value();
+  params.printInterval = mGBParams.mPrintInterval.value();
+  params.sPairGroupSize = mSPairGroupSize.value();
+  params.reducerMemoryQuantum = mGBParams.mMemoryQuantum.value();
+  params.useAutoTopReduction = mAutoTopReduce.value();
+  params.useAutoTailReduction = mAutoTailReduce.value();
+  params.callback = nullptr;
+
+  const auto gb = mModule.value() ?
+    computeModuleGBClassicAlg(std::move(basis), params) :
+    computeGBClassicAlg(std::move(basis), params);
 
   if (mGBParams.mOutputResult.value()) {
-    // output Groebner basis into .gb file.
-
-    std::string basisFileName = projectName + ".gb";
-    std::ofstream out(basisFileName);
-    output(out, alg.basis());
+    std::ofstream out(projectName + ".gb");
+    MathicIO<>().writeBasis(gb, mModule.value(), out);
   }
 }
 
@@ -134,6 +144,8 @@ void GBAction::pushBackParameters(
   parameters.push_back(&mAutoTopReduce);
   parameters.push_back(&mSPairGroupSize);
   parameters.push_back(&mMinMatrixToStore);
+  parameters.push_back(&mModule);
 }
 
 MATHICGB_NAMESPACE_END
+  
\ No newline at end of file
diff --git a/src/cli/GBAction.hpp b/src/cli/GBAction.hpp
index 4afbe0a..252344f 100755
--- a/src/cli/GBAction.hpp
+++ b/src/cli/GBAction.hpp
@@ -37,6 +37,7 @@ private:
   //mic::IntegerParameter mTermOrder;
   mathic::IntegerParameter mSPairGroupSize;
   mathic::IntegerParameter mMinMatrixToStore;
+  mic::BoolParameter mModule;
 };
 
 MATHICGB_NAMESPACE_END
diff --git a/src/cli/GBCommonParams.cpp b/src/cli/GBCommonParams.cpp
index 91ecef8..6ad07ad 100755
--- a/src/cli/GBCommonParams.cpp
+++ b/src/cli/GBCommonParams.cpp
@@ -10,51 +10,68 @@
 MATHICGB_NAMESPACE_BEGIN
 
 GBCommonParams::GBCommonParams():
-  mPreferSparseReducers("preferSparseReducers",
+  mPreferSparseReducers(
+    "preferSparseReducers",
     "If true, always use the sparsest reducer in polynomial reduction. "
-    "This option impacts both classic and signature constrained "
-    "polynomial reduction. Ties are broken by taking the oldest reducer. "
-    "If this option is false, the oldest reducer is always used.",
-    true),
+      "This option impacts both classic and signature constrained "
+      "polynomial reduction. Ties are broken by taking the oldest reducer. "
+      "If this option is false, the oldest reducer is always used.",
+    true
+  ),
 
-  mOutputResult("outputResult",
+  mOutputResult(
+    "outputResult",
     "If true, output the resulting Groebner or signature basis "
-    "to the file <projectName>.gb and in the signature basis "
-    "case, the signatures of the syzygies are placed in <projectName>.syz",
-    false),
+      "to the file <projectName>.gb and in the signature basis "
+      "case, the signatures of the syzygies are placed in <projectName>.syz",
+    false
+  ),
 
-  mSPairQueue("spairQueue",
+  mSPairQueue(
+    "spairQueue",
     "The priority queue used to order S-pairs.\n"
-    "  0   tournament tree in front of triangle\n"
-    "  1   heap in front of triangle\n"
-    "  2   tournament tree\n"
-    "  3   heap\n",
-    0),
+      "  0   tournament tree in front of triangle\n"
+      "  1   heap in front of triangle\n"
+      "  2   tournament tree\n"
+      "  3   heap\n",
+    0
+  ),
 
-  mBreakAfter("breakAfter",
+  mBreakAfter(
+    "breakAfter",
     "Stop the computation after this many elements have been added to "
-    "the basis. The computation runs uninterrupted if the value is zero.",
-    0),
+      "the basis. The computation runs uninterrupted if the value is zero.",
+    0
+  ),
 
-  mPrintInterval("printInterval",
+  mPrintInterval(
+    "printInterval",
     "Print information about the computation every time this many S-pair "
-    "reductions have been performed. Do not print information like this "
-    "during the computation if the value is zero.",
-    0),
+      "reductions have been performed and at the end. Do not print information "
+      "like this during the computation if the value is zero.",
+    std::numeric_limits<decltype(mPrintInterval.value())>::max()
+  ),
 
-  mMonomialTable("monomialTable",
+  mMonomialTable(
+    "monomialTable",
     "The kind of monomial table data structure to use.\n",
-    2),
+    2
+  ),
 
-  mMonoLookup("divisorLookup",
+  mMonoLookup(
+    "divisorLookup",
     "The monomial lookup data structure to use.\n",
-    2),
+    2
+  ),
 
-  mReducer("reducer",
+  mReducer(
+    "reducer",
     "The data structure to use for polynomial reduction.\n",
-    4),
+    4
+  ),
 
-  mMemoryQuantum("memoryQuantumForReducer",
+  mMemoryQuantum(
+    "memoryQuantumForReducer",
     "Specifies how many items to allocate memory for at a time for the reducer.",
     1024 * 1024)
 {
diff --git a/src/cli/SigGBAction.cpp b/src/cli/SigGBAction.cpp
index 216a402..7725832 100755
--- a/src/cli/SigGBAction.cpp
+++ b/src/cli/SigGBAction.cpp
@@ -21,11 +21,13 @@ SigGBAction::SigGBAction():
     "the S-pair would otherwise cause a polynomial reduction to occur. ",
     false),
 
-  mPostponeKoszul("postponeKoszul",
+  mPostponeKoszul(
+    "postponeKoszul",
     "Postpone the construction of Koszul syzygy signatures.",
     true),
 
-  mUseBaseDivisors("useBaseDivisors",
+  mUseBaseDivisors(
+    "useBaseDivisors",
     "Use high ratio and low ratio base divisors to eliminate "
     "S-spairs quickly based on signature.",
     true),
@@ -78,28 +80,27 @@ void SigGBAction::performAction() {
   alg.displayStats(std::cout);
   alg.displayPaperStats(std::cout);
   {
-    std::ofstream statsOut((mParams.inputFileNameStem(0) + ".stats").c_str());
+    std::ofstream statsOut(mParams.inputFileNameStem(0) + ".stats");
     alg.displayStats(statsOut);
     alg.displayPaperStats(statsOut);
   }
 
-  if (mGBParams.mOutputResult.value())
+  if (mGBParams.mOutputResult.value()) {
+    // print basis
     {
-      // print basis
-      {
-        std::ofstream ogb((mParams.inputFileNameStem(0) + ".gb").c_str());
-        ogb << "-- gb: ----\n";
-        alg.getGB()->display(ogb);
-      }
+      std::ofstream ogb(mParams.inputFileNameStem(0) + ".gb");
+      ogb << "-- gb: ----\n";
+      alg.getGB()->display(ogb);
+    }
       
-      // print syzygy basis
-      {
-        std::ofstream syzygyOut((mParams.inputFileNameStem(0) + ".syz").c_str());
-        syzygyOut << "-- syz: ----\n";
-        alg.getSyzTable()->display(syzygyOut);
-        syzygyOut << std::endl;
-      }
+    // print syzygy basis
+    {
+      std::ofstream syzygyOut(mParams.inputFileNameStem(0) + ".syz");
+      syzygyOut << "-- syz: ----\n";
+      alg.getSyzTable()->display(syzygyOut);
+      syzygyOut << std::endl;
     }
+  }
 }
 
 const char* SigGBAction::staticName() {
diff --git a/src/mathicgb.cpp b/src/mathicgb.cpp
index c59a16e..17f4bce 100755
--- a/src/mathicgb.cpp
+++ b/src/mathicgb.cpp
@@ -850,7 +850,7 @@ namespace mgbi {
 }
 
 namespace {
-  class CallbackAdapter : public mgb::ClassicGBAlg::Callback {
+  class CallbackAdapter {
   public:
     typedef mgb::GroebnerConfiguration::Callback::Action Action;
 
@@ -865,7 +865,7 @@ namespace {
     const bool isNull() const {return mCallback == 0;}
     Action lastAction() const {return mLastAction;}
 
-    virtual bool call() {
+    bool operator()() {
       if (isNull())
         return true;
       mLastAction = mCallback(mData);
@@ -925,20 +925,26 @@ namespace mgbi {
       PimplOf()(conf).mCallback
     );
 
-    // Set up and configure algorithm
-    ClassicGBAlg alg(basis, *reducer, 2, true, 0);
-    alg.setReducerMemoryQuantum(100 * 1024);
-    alg.setUseAutoTopReduction(true);
-    alg.setUseAutoTailReduction(false);
-    alg.setSPairGroupSize(conf.maxSPairGroupSize());
+    ClassicGBAlgParams params;
+    params.reducer = reducer.get();
+    params.monoLookupType = 2;
+    params.preferSparseReducers = true;
+    params.sPairQueueType = 0;
+    params.breakAfter = 0;
+    params.printInterval = 0;
+    params.sPairGroupSize = conf.maxSPairGroupSize();
+    params.reducerMemoryQuantum = 100 * 1024;
+    params.useAutoTopReduction = true;
+    params.useAutoTailReduction = false;
+    params.callback = nullptr;
     if (!callback.isNull())
-      alg.setCallback(&callback);
+      params.callback = [&callback](){return callback();};
+
+    auto gb = computeGBClassicAlg(std::move(basis), params);
 
-    // Compute Groebner basis
-    alg.computeGrobnerBasis();
     typedef mgb::GroebnerConfiguration::Callback::Action Action;
     if (callback.lastAction() != Action::StopWithNoOutputAction) {
-      PimplOf()(output).basis = alg.basis().toBasisAndRetireAll();
+      PimplOf()(output).basis = make_unique<Basis>(std::move(gb));
       PimplOf()(output).tmpTerm =
         make_unique_array<GConf::Exponent>(basis.ring().varCount());
       return true;
diff --git a/src/mathicgb/ClassicGBAlg.cpp b/src/mathicgb/ClassicGBAlg.cpp
index d6c20d3..004fd80 100755
--- a/src/mathicgb/ClassicGBAlg.cpp
+++ b/src/mathicgb/ClassicGBAlg.cpp
@@ -3,10 +3,16 @@
 #include "stdinc.h"
 #include "ClassicGBAlg.hpp"
 
+#include "Reducer.hpp"
+#include "SPairs.hpp"
+#include "PolyBasis.hpp"
 #include "Basis.hpp"
 #include "LogDomain.hpp"
 #include "MathicIO.hpp"
 #include <iostream>
+#include <mathic.h>
+#include <memory>
+#include <vector>
 
 MATHICGB_DEFINE_LOG_DOMAIN(
   SPairDegree,
@@ -16,6 +22,91 @@ MATHICGB_DEFINE_LOG_DOMAIN(
 
 MATHICGB_NAMESPACE_BEGIN
 
+/// Calculates a classic Grobner basis using Buchberger's algorithm.
+class ClassicGBAlg {
+public:
+  ClassicGBAlg(
+    const Basis& basis,
+    Reducer& reducer,
+    int monoLookupType,
+    bool preferSparseReducers,
+    size_t queueType
+  );
+
+  // Replaces the current basis with a Grobner basis of the same ideal.
+  void computeGrobnerBasis();
+
+  // How many S-pairs were not eliminated before reduction of the
+  // corresponding S-polynomial.
+  unsigned long long sPolyReductionCount() const {return mSPolyReductionCount;}
+
+  // Returns the current basis.
+  PolyBasis& basis() {return mBasis;}
+
+  // Shows statistics on what the algorithm has done.
+  void printStats(std::ostream& out) const;
+
+  void printMemoryUse(std::ostream& out) const;
+
+  size_t getMemoryUse() const;
+
+  void setBreakAfter(unsigned int elements) {
+    mBreakAfter = elements;
+  }
+
+  void setPrintInterval(unsigned int reductions) {
+    mPrintInterval = reductions;
+  }
+
+  /// A value of zero means to let the algorithm decide a reasonable
+  /// value based on the other settings.
+  void setSPairGroupSize(unsigned int groupSize);
+
+  void setReducerMemoryQuantum(size_t memoryQuantum) {
+    mReducer.setMemoryQuantum(memoryQuantum);
+  }
+
+  void setUseAutoTopReduction(bool value) {
+    mUseAutoTopReduction = value;
+  }
+
+  void setUseAutoTailReduction(bool value) {
+    mUseAutoTailReduction = value;
+  }
+
+  /// callback is called every once in a while and then it has the
+  /// option of stopping the computation. callback can be null, in
+  /// which case no call is made and the computation continues.
+  void setCallback(std::function<bool(void)> callback) {
+    mCallback = std::move(callback);
+  }
+
+private:
+  std::function<bool(void)> mCallback;
+  unsigned int mBreakAfter;
+  unsigned int mPrintInterval;
+  unsigned int mSPairGroupSize;
+  bool mUseAutoTopReduction;
+  bool mUseAutoTailReduction;
+
+  // Perform a step of the algorithm.
+  void step();
+
+  void autoTailReduce();
+
+  void insertReducedPoly(std::unique_ptr<Poly> poly);
+
+  // clears polynomials.
+  void insertPolys(std::vector<std::unique_ptr<Poly> >& polynomials);
+
+  const PolyRing& mRing;
+  Reducer& mReducer;
+  PolyBasis mBasis;
+  SPairs mSPairs;
+  mic::Timer mTimer;
+  unsigned long long mSPolyReductionCount;
+};
+
 ClassicGBAlg::ClassicGBAlg(
   const Basis& basis,
   Reducer& reducer,
@@ -23,7 +114,7 @@ ClassicGBAlg::ClassicGBAlg(
   bool preferSparseReducers,
   size_t queueType
 ):
-  mCallback(0),
+  mCallback(nullptr),
   mBreakAfter(0),
   mPrintInterval(0),
   mSPairGroupSize(reducer.preferredSetSize()),
@@ -77,8 +168,8 @@ void ClassicGBAlg::insertPolys
   }
 
   std::vector<size_t> toRetire;
-  std::vector<std::unique_ptr<Poly> > toReduce;
-  std::vector<std::unique_ptr<Poly> > toInsert;
+  std::vector<std::unique_ptr<Poly>> toReduce;
+  std::vector<std::unique_ptr<Poly>> toInsert;
   std::swap(toInsert, polynomials);
 
   while (!toInsert.empty()) {
@@ -215,7 +306,7 @@ void ClassicGBAlg::computeGrobnerBasis() {
     autoTailReduce();
 
   while (!mSPairs.empty()) {
-    if (mCallback != 0 && !mCallback->call())
+    if (mCallback != nullptr && !mCallback())
       break;
 
     step();
@@ -228,7 +319,8 @@ void ClassicGBAlg::computeGrobnerBasis() {
     if (mPrintInterval != 0 && (++counter % mPrintInterval) == 0)
       printStats(std::cerr);
   }
-  //printStats(std::cerr);
+  if (mPrintInterval != 0)
+    printStats(std::cerr);
   //mReducer->dump();
   /*
   for (size_t i = 0; i < mBasis.size(); ++i)
@@ -553,4 +645,34 @@ void ClassicGBAlg::printMemoryUse(std::ostream& out) const
   out << "*** Memory use by component ***\n" << pr << std::flush;
 }
 
+Basis computeGBClassicAlg(
+  Basis&& inputBasis,
+  ClassicGBAlgParams params
+) {
+  ClassicGBAlg alg(
+    inputBasis,
+    *params.reducer,
+    params.monoLookupType,
+    params.preferSparseReducers,
+    params.sPairQueueType
+  );
+  alg.setBreakAfter(params.breakAfter);
+  alg.setPrintInterval(params.printInterval);
+  alg.setSPairGroupSize(params.sPairGroupSize);
+  alg.setReducerMemoryQuantum(params.reducerMemoryQuantum);
+  alg.setUseAutoTopReduction(params.useAutoTopReduction);
+  alg.setUseAutoTailReduction(params.useAutoTailReduction);
+  alg.setCallback(params.callback);
+
+  alg.computeGrobnerBasis();
+  return std::move(*alg.basis().toBasisAndRetireAll());
+}
+
+Basis computeModuleGBClassicAlg(
+  Basis&& inputBasis,
+  ClassicGBAlgParams params
+) {
+  return computeGBClassicAlg(std::move(inputBasis), params);
+}
+
 MATHICGB_NAMESPACE_END
diff --git a/src/mathicgb/ClassicGBAlg.hpp b/src/mathicgb/ClassicGBAlg.hpp
index b74674f..620999f 100755
--- a/src/mathicgb/ClassicGBAlg.hpp
+++ b/src/mathicgb/ClassicGBAlg.hpp
@@ -3,105 +3,30 @@
 #ifndef MATHICGB_CLASSIC_GB_ALG_GUARD
 #define MATHICGB_CLASSIC_GB_ALG_GUARD
 
-#include "Reducer.hpp"
-#include "SPairs.hpp"
-#include "PolyBasis.hpp"
-#include <mathic.h>
-#include <memory>
-#include <ostream>
-#include <vector>
+#include <functional>
 
 MATHICGB_NAMESPACE_BEGIN
 
+class Reducer;
 class Basis;
 
-/// Calculates a classic Grobner basis using Buchberger's algorithm.
-class ClassicGBAlg {
-public:
-  ClassicGBAlg(
-    const Basis& basis,
-    Reducer& reducer,
-    int monoLookupType,
-    bool preferSparseReducers,
-    size_t queueType
-  );
-
-  // Replaces the current basis with a Grobner basis of the same ideal.
-  void computeGrobnerBasis();
-
-  // How many S-pairs were not eliminated before reduction of the
-  // corresponding S-polynomial.
-  unsigned long long sPolyReductionCount() const {return mSPolyReductionCount;}
-
-  // Returns the current basis.
-  PolyBasis& basis() {return mBasis;}
-
-  // Shows statistics on what the algorithm has done.
-  void printStats(std::ostream& out) const;
-
-  void printMemoryUse(std::ostream& out) const;
-
-  size_t getMemoryUse() const;
-
-  void setBreakAfter(unsigned int elements) {
-    mBreakAfter = elements;
-  }
-
-  void setPrintInterval(unsigned int reductions) {
-    mPrintInterval = reductions;
-  }
-
-  /// A value of zero means to let the algorithm decide a reasonable
-  /// value based on the other settings.
-  void setSPairGroupSize(unsigned int groupSize);
-
-  void setReducerMemoryQuantum(size_t memoryQuantum) {
-    mReducer.setMemoryQuantum(memoryQuantum);
-  }
-
-  void setUseAutoTopReduction(bool value) {
-    mUseAutoTopReduction = value;
-  }
-
-  void setUseAutoTailReduction(bool value) {
-    mUseAutoTailReduction = value;
-  }
-
-  class Callback {
-  public:
-    /// Stop the computation if call return false.
-    virtual bool call() = 0;
-  };
-  /// callback is called every once in a while and then it has the
-  /// option of stopping the computation. callback can be null, in
-  /// which case no call is made and the computation continues.
-  void setCallback(Callback* callback) {mCallback = callback;}
-
-private:
-  Callback* mCallback;
-  unsigned int mBreakAfter;
-  unsigned int mPrintInterval;
-  unsigned int mSPairGroupSize;
-  bool mUseAutoTopReduction;
-  bool mUseAutoTailReduction;
-
-  // Perform a step of the algorithm.
-  void step();
-
-  void autoTailReduce();
-
-  void insertReducedPoly(std::unique_ptr<Poly> poly);
-
-  // clears polynomials.
-  void insertPolys(std::vector<std::unique_ptr<Poly> >& polynomials);
-
-  const PolyRing& mRing;
-  Reducer& mReducer;
-  PolyBasis mBasis;
-  SPairs mSPairs;
-  mic::Timer mTimer;
-  unsigned long long mSPolyReductionCount;
+struct ClassicGBAlgParams {
+  Reducer* reducer;
+  int monoLookupType;
+  bool preferSparseReducers;
+  size_t sPairQueueType;
+
+  unsigned int breakAfter;
+  unsigned int printInterval;
+  unsigned int sPairGroupSize;
+  size_t reducerMemoryQuantum;
+  bool useAutoTopReduction;
+  bool useAutoTailReduction;
+  std::function<bool(void)> callback;
 };
 
+Basis computeGBClassicAlg(Basis&& inputBasis, ClassicGBAlgParams params);
+Basis computeModuleGBClassicAlg(Basis&& inputBasis, ClassicGBAlgParams params);
+
 MATHICGB_NAMESPACE_END
 #endif
diff --git a/src/mathicgb/MonoMonoid.hpp b/src/mathicgb/MonoMonoid.hpp
index ea09848..8d7ba55 100755
--- a/src/mathicgb/MonoMonoid.hpp
+++ b/src/mathicgb/MonoMonoid.hpp
@@ -636,8 +636,10 @@ public:
   }
 
   /// Returns true if a divides b. Equal monomials divide each other.
+  /// Doesn't take component into account - see dividesWithComponent.
   bool divides(ConstMonoRef div, ConstMonoRef into) const {
-    // todo: enable this when the code works with it
+    // todo: enable this when the code works with it - see 
+    // dividesWithComponent.
     //if (HasComponent && component(div) != component(into))
     //  return false;
     for (auto i = exponentsIndexBegin(); i < exponentsIndexEnd(); ++i)
@@ -646,6 +648,24 @@ public:
     return true;
   }
 
+  /// Returns true if a divides b. Equal monomials divide each other.
+  /// This also takes the component into account. Once the code base is
+  /// fixed to properly observe the distinction between monomials and
+  /// module monomials, there will only need to be the one divides()
+  /// which takes component into account if and only if HasComponent is
+  /// true. For now, we're left with this imperfect solution of two
+  /// overloads.
+  ///
+  /// @todo: get rid of this method.
+  bool dividesWithComponent(ConstMonoRef div, ConstMonoRef into) const {
+    if (HasComponent && component(div) != component(into))
+      return false;
+    for (auto i = exponentsIndexBegin(); i < exponentsIndexEnd(); ++i)
+      if (access(div, i) > access(into, i))
+        return false;
+    return true;
+  }
+
   template<class MonoidA>
   bool divides(
     const MonoidA& monoidA,
@@ -672,6 +692,30 @@ public:
     return true;
   }
 
+  /// @todo: get rid of this -- see other overload.
+  template<class MonoidA>
+  bool dividesWithComponent(
+    const MonoidA& monoidA,
+    typename MonoidA::ConstMonoRef a,
+    ConstMonoRef b
+  ) const {
+    // todo: fix other divisibility functions to work properly for component too.
+    MATHICGB_ASSERT(monoidA.varCount() == varCount());
+    MATHICGB_ASSERT(!MonoidA::HasComponent || HasComponent);
+    MATHICGB_ASSERT(monoidA.debugValid(a));
+    MATHICGB_ASSERT(debugValid(b));
+    if (
+      MonoidA::HasComponent &&
+      HasComponent &&
+      monoidA.component(a) != component(b)
+    )
+      return false;
+    for (VarIndex var = 0; var < varCount(); ++var)
+      if (monoidA.exponent(a, var) > exponent(b, var))
+        return false;
+    return true;
+  }
+
   /// Returns true if div divides lcm(a, b).
   bool dividesLcm(ConstMonoRef div, ConstMonoRef a, ConstMonoRef b) const {
     MATHICGB_ASSERT(debugLcmCheck(*this, a, *this, b));
diff --git a/src/mathicgb/Poly.hpp b/src/mathicgb/Poly.hpp
index 786b740..2c70a33 100755
--- a/src/mathicgb/Poly.hpp
+++ b/src/mathicgb/Poly.hpp
@@ -255,6 +255,12 @@ public:
   ConstTermIterator end() const {return makeZip(coefEnd(), monoEnd());}
   ConstTermIteratorRange termRange() const {return range(begin(), end());}
 
+  NewConstTerm leadTerm() const {
+    MATHICGB_ASSERT(!isZero());
+    NewConstTerm term = {leadCoef(), leadMono().ptr()};
+    return term;
+  }
+
 private:
   friend bool operator==(const Poly &a, const Poly &b);
 
diff --git a/src/mathicgb/PolyBasis.cpp b/src/mathicgb/PolyBasis.cpp
index 73b84ea..1c024c3 100755
--- a/src/mathicgb/PolyBasis.cpp
+++ b/src/mathicgb/PolyBasis.cpp
@@ -125,7 +125,7 @@ size_t PolyBasis::classicReducer(ConstMonoRef mono) const {
 size_t PolyBasis::divisorSlow(ConstMonoRef mono) const {
   const size_t stop = size();
   for (size_t i = 0; i != stop; ++i)
-    if (!retired(i) && monoid().divides(leadMono(i), mono))
+    if (!retired(i) && monoid().dividesWithComponent(leadMono(i), mono))
       return i;
   return static_cast<size_t>(-1);
 }
diff --git a/src/mathicgb/SPairs.cpp b/src/mathicgb/SPairs.cpp
index 0f2c18f..a2edba4 100755
--- a/src/mathicgb/SPairs.cpp
+++ b/src/mathicgb/SPairs.cpp
@@ -233,6 +233,10 @@ void SPairs::addPairs(size_t newGen) {
     if (mBasis.retired(oldGen))
       continue;
     auto oldLead = mBasis.leadMono(oldGen);
+    if (monoid().component(newLead) != monoid().component(oldLead)) {
+      mEliminated.setBit(newGen, oldGen, true);
+      continue;
+    }
     if (monoid().relativelyPrime(newLead, oldLead)) {
       ++mStats.relativelyPrimeHits;
       mEliminated.setBit(newGen, oldGen, true);
@@ -268,6 +272,10 @@ bool SPairs::simpleBuchbergerLcmCriterion(
   size_t b,
   BareMonoid::ConstMonoRef lcmAB
 ) const {
+  MATHICGB_ASSERT(
+    monoid().component(mBasis.leadMono(a)) ==
+      monoid().component(mBasis.leadMono(b))
+  );
   MATHICGB_ASSERT(a < mBasis.size());
   MATHICGB_ASSERT(b < mBasis.size());
   MATHICGB_ASSERT(a != b);
@@ -312,6 +320,7 @@ bool SPairs::simpleBuchbergerLcmCriterion(
       auto leadA = mBasis.leadMono(mA);
       auto leadB = mBasis.leadMono(mB);
       auto leadC = mBasis.leadMono(index);
+
       if (
         !mSPairs.eliminated(index, mA) &&
         mMonoid.dividesLcm(leadB, leadC, leadA)
@@ -374,7 +383,7 @@ bool SPairs::simpleBuchbergerLcmCriterion(
       if (
           !applies &&
           !mBasis.retired(cacheB) &&
-          mBareMonoid.divides
+          mBareMonoid.dividesWithComponent
             (monoid(), mBasis.leadMono(cacheB), criterion.lcmAB())
       )
         applies = !criterion.Criterion::proceed(cacheB);
@@ -383,7 +392,7 @@ bool SPairs::simpleBuchbergerLcmCriterion(
       if (
         !applies &&
         !mBasis.retired(cacheA) &&
-        mBareMonoid.divides
+        mBareMonoid.dividesWithComponent
           (monoid(), mBasis.leadMono(cacheA), criterion.lcmAB())
       ) {
         applies = !criterion.Criterion::proceed(cacheA);
@@ -426,6 +435,10 @@ bool SPairs::simpleBuchbergerLcmCriterion(
 }
 
 bool SPairs::simpleBuchbergerLcmCriterionSlow(size_t a, size_t b) const {
+  MATHICGB_ASSERT(
+    monoid().component(mBasis.leadMono(a)) ==
+      monoid().component(mBasis.leadMono(b))
+  );
   MATHICGB_ASSERT(a < mBasis.size());
   MATHICGB_ASSERT(b < mBasis.size());
   MATHICGB_ASSERT(a != b);
@@ -446,7 +459,7 @@ bool SPairs::simpleBuchbergerLcmCriterionSlow(size_t a, size_t b) const {
   for (; i < stop; ++i) {
     if (mBasis.retired(i))
       continue;
-    if (!bareMonoid().divides(monoid(), mBasis.leadMono(i), *lcmAB))
+    if (!bareMonoid().dividesWithComponent(monoid(), mBasis.leadMono(i), *lcmAB))
       continue;
     if (i == a || i == b)
       continue;
@@ -611,7 +624,7 @@ bool SPairs::advancedBuchbergerLcmCriterionSlow(size_t a, size_t b) const {
   for (size_t i = 0; i != stop; ++i) {
     if (mBasis.retired(i))
       continue;
-    if (!monoid().divides(mBasis.leadMono(i), *lcmAB))
+    if (!monoid().dividesWithComponent(mBasis.leadMono(i), *lcmAB))
       continue;
     Connection con = NotConnected;
     if (i == a) {
diff --git a/src/mathicgb/SPairs.hpp b/src/mathicgb/SPairs.hpp
index 8bfef5d..aa7ec0f 100755
--- a/src/mathicgb/SPairs.hpp
+++ b/src/mathicgb/SPairs.hpp
@@ -30,13 +30,11 @@ public:
   /// lcms such as hash and degree is expensive (unlike for a product), it is
   /// worthwhile to disable those characteristics that we do not need.
   typedef MonoMonoid<Exponent, true, false, false> BareMonoid;
-  //typedef Monoid BareMonoid;
 
   /// This monoid is used to order S-pairs by their lcm. Here we need to
   /// to store the ordering data for fast comparison, but we do not need
   /// hashes.
   typedef MonoMonoid<Exponent, true, false, true> OrderMonoid;
-  //typedef Monoid OrderMonoid;
 
   SPairs(const PolyBasis& basis, bool preferSparseSPairs);
 
diff --git a/src/mathicgb/StaticMonoMap.hpp b/src/mathicgb/StaticMonoMap.hpp
index cb89a83..a87d2dc 100755
--- a/src/mathicgb/StaticMonoMap.hpp
+++ b/src/mathicgb/StaticMonoMap.hpp
@@ -79,19 +79,19 @@ private:
     }
 
     bool divides(const Monomial& a, const Monomial& b) const {
-      return monoid().divides(a, b);
+      return monoid().dividesWithComponent(a, b);
     }
 
     bool divides(const Entry& a, const Monomial& b) const {
-      return monoid().divides(a.mono(), b);
+      return monoid().dividesWithComponent(a.mono(), b);
     }
 
     bool divides(const Monomial& a, const Entry& b) const {
-      return monoid().divides(a, b.mono());
+      return monoid().dividesWithComponent(a, b.mono());
     }
 
     bool divides(const Entry& a, const Entry& b) const {
-      return monoid().divides(a.mono(), b.mono());
+      return monoid().dividesWithComponent(a.mono(), b.mono());
     }
 
     bool getSortOnInsert() const {return false;}
diff --git a/src/test/gb-test.cpp b/src/test/gb-test.cpp
index 649bb1f..9aa0d88 100755
--- a/src/test/gb-test.cpp
+++ b/src/test/gb-test.cpp
@@ -266,20 +266,32 @@ spairQueue	reducerType	divLookup	monTable	buchberger	postponeKoszul	useBaseDivis
     if (buchberger) {
       const auto reducer = Reducer::makeReducer
         (Reducer::reducerType(reducerType), ring);
-      ClassicGBAlg alg(
-        std::move(basis),
-        *reducer,
-        divLookup,
-        preferSparseReducers,
-        spairQueue
-      );
-      alg.setUseAutoTopReduction(autoTopReduce);
-      alg.setUseAutoTailReduction(autoTailReduce);
-      alg.setSPairGroupSize(sPairGroupSize);
-      alg.computeGrobnerBasis();
-      std::unique_ptr<Basis> initialIdeal =
-        alg.basis().initialIdeal();
-      EXPECT_EQ(initialIdealStr, toString(initialIdeal.get()))
+
+      ClassicGBAlgParams params;
+      params.reducer = reducer.get();
+      params.monoLookupType = divLookup;
+      params.preferSparseReducers = preferSparseReducers;
+      params.sPairQueueType = spairQueue;
+      params.breakAfter = 0;
+      params.printInterval = 0;
+      params.sPairGroupSize = sPairGroupSize;
+      params.reducerMemoryQuantum = 100 * 1024;
+      params.useAutoTopReduction = autoTopReduce;
+      params.useAutoTailReduction = autoTailReduce;
+      params.callback = nullptr;
+
+      auto gb = computeGBClassicAlg(std::move(basis), params);
+
+      Basis initialIdeal(gb.ring());
+      for (size_t i = 0; i < gb.size(); ++i) {
+        auto poly = make_unique<Poly>(gb.ring());
+        auto leadTerm = gb.getPoly(i)->leadTerm();
+        leadTerm.coef = gb.ring().field().one();
+        poly->append(leadTerm);
+        initialIdeal.insert(std::move(poly));
+      }
+      initialIdeal.sort();
+      EXPECT_EQ(initialIdealStr, toString(&initialIdeal))
         << reducerType << ' ' << divLookup << ' '
         << monTable << ' ' << postponeKoszul << ' ' << useBaseDivisors;
     } else {

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