[mathicgb] 338/393: Moving to use of lambdas in DivLookup.hpp

Doug Torrance dtorrance-guest at moszumanska.debian.org
Fri Apr 3 15:59:31 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 c14e36a43d9194e1c03af102bc273d5c97bf75b5
Author: Bjarke Hammersholt Roune <bjarkehr.code at gmail.com>
Date:   Tue Aug 27 15:37:54 2013 +0200

    Moving to use of lambdas in DivLookup.hpp
---
 src/mathicgb/DivLookup.hpp     | 314 ++++++++++++++++++-----------------------
 src/mathicgb/DivisorLookup.hpp |  46 +++---
 src/mathicgb/PolyRing.hpp      |   8 ++
 src/mathicgb/SPairs.cpp        |   6 +-
 4 files changed, 171 insertions(+), 203 deletions(-)

diff --git a/src/mathicgb/DivLookup.hpp b/src/mathicgb/DivLookup.hpp
index 785d94b..d15213e 100755
--- a/src/mathicgb/DivLookup.hpp
+++ b/src/mathicgb/DivLookup.hpp
@@ -23,6 +23,8 @@ template<bool AR, bool DM>
 class DivLookupConfiguration {
 public:
   typedef PolyRing::Monoid Monoid;
+  typedef Monoid::ConstMonoPtr ConstMonoPtr;
+  typedef Monoid::ConstMonoRef ConstMonoRef;
 
   DivLookupConfiguration(
     const Monoid& monoid,
@@ -33,7 +35,7 @@ public:
     mSigBasis(0),
     mMonoid(monoid),
     mType(type),
-    _preferSparseReducers(preferSparseReducers)
+    mPreferSparseReducers(preferSparseReducers)
   {}
 
   void setBasis(const PolyBasis& basis) {
@@ -54,23 +56,31 @@ public:
     setBasis(sigBasis.basis());
   }
 
-  const SigPolyBasis* sigBasis() const {return mSigBasis;}
-  const PolyBasis* basis() const {return mBasis;}
+  const SigPolyBasis& sigBasis() const {
+    MATHICGB_ASSERT(mSigBasis != 0);
+    return *mSigBasis;
+  }
+  
+  const PolyBasis& basis() const {
+    MATHICGB_ASSERT(mBasis != 0);
+    return *mBasis;
+  }
+
   const Monoid& monoid() const {return mMonoid;}
   int type() const {return mType;}
-  bool preferSparseReducers() const {return _preferSparseReducers;}
+  bool preferSparseReducers() const {return mPreferSparseReducers;}
 
   // *** Interface expected by mathic follows below
 
   typedef int Exponent;
-  typedef const_monomial Monomial;
+  typedef ConstMonoRef Monomial;
   struct Entry {
-    const_monomial monom;
-    size_t index;
+    Entry(): monom(), index(static_cast<size_t>(-1)) {}
+    Entry(ConstMonoRef monom0, size_t index0):
+      monom(monom0.ptr()), index(index0) {}
 
-    Entry(): monom(0), index(static_cast<size_t>(-1)) {}
-    Entry(const_monomial monom0, size_t index0):
-      monom(monom0), index(index0) {}
+    ConstMonoPtr monom;
+    size_t index;
   };
 
   Exponent getExponent(const Monomial& m, size_t var) const {
@@ -78,7 +88,7 @@ public:
   }
 
   Exponent getExponent(const Entry& e, size_t var) const {
-    return monoid().exponent(e.monom, var);
+    return monoid().exponent(*e.monom, var);
   }
 
   bool divides(const Monomial& a, const Monomial& b) const {
@@ -86,15 +96,15 @@ public:
   }
 
   bool divides(const Entry& a, const Monomial& b) const {
-    return monoid().divides(a.monom, b);
+    return monoid().divides(*a.monom, b);
   }
 
   bool divides(const Monomial& a, const Entry& b) const {
-    return monoid().divides(a, b.monom);
+    return monoid().divides(a, *b.monom);
   }
 
   bool divides(const Entry& a, const Entry& b) const {
-    return monoid().divides(a.monom, b.monom);
+    return monoid().divides(*a.monom, *b.monom);
   }
 
   bool getSortOnInsert() const {return false;}
@@ -125,107 +135,148 @@ private:
   SigPolyBasis const* mSigBasis;
   const Monoid& mMonoid;
   const int mType;
-  bool const _preferSparseReducers;
+  bool const mPreferSparseReducers;
 };
 
-template<class Finder>
+template<class BaseLookup>
+class DivLookup;
+
+template<class BL>
 class DivLookup : public DivisorLookup {
- public:
-  typedef typename Finder::Monomial Monomial;
-  typedef typename Finder::Entry Entry;
-  typedef typename Finder::Configuration Configuration;
-  typedef Configuration C;
-
-  DivLookup(const Configuration &C) :
-        _finder(C)
-  {
-    MATHICGB_ASSERT(!C.UseTreeDivMask || C.UseDivMask);
-  }
+public:
+  typedef BL BaseLookup;
+  typedef typename BaseLookup::Monomial Monomial;
+  typedef typename BaseLookup::Entry Entry;
+  typedef typename BaseLookup::Configuration Configuration;
+
+  static_assert
+    (!Configuration::UseTreeDivMask || Configuration::UseDivMask, "");
 
-  ~DivLookup() {}
+  DivLookup(const Configuration& c): mLookup(c) {}
 
   virtual void setBasis(const PolyBasis& basis) {
-    _finder.getConfiguration().setBasis(basis);
+    mLookup.getConfiguration().setBasis(basis);
   }
 
   virtual void setSigBasis(const SigPolyBasis& sigBasis) {
-    _finder.getConfiguration().setSigBasis(sigBasis);
+    mLookup.getConfiguration().setSigBasis(sigBasis);
   }
 
+  virtual int type() const {return mLookup.getConfiguration().type();}
 
-  virtual int type() const {return _finder.getConfiguration().type();}
+  template<class Lambda>
+  class LambdaWrap {
+  public:
+    LambdaWrap(Lambda& lambda): mLambda(lambda) {}
+    bool proceed(const Entry& entry) const {return mLambda(entry);}
+  private:
+    Lambda& mLambda;
+  };
+  template<class Lambda>
+  static LambdaWrap<Lambda> lambdaWrap(Lambda& lambda) {
+    return LambdaWrap<Lambda>(lambda);
+  }
 
   virtual void lowBaseDivisors(
     std::vector<size_t>& divisors,
     size_t maxDivisors,
     size_t newGenerator
   ) const {
-    const SigPolyBasis* GB = _finder.getConfiguration().sigBasis();
-
-    const_monomial sigNew = GB->getSignature(newGenerator);
+    const auto& basis = mLookup.getConfiguration().sigBasis();
+    MATHICGB_ASSERT(newGenerator < basis.size());
 
-    MATHICGB_ASSERT(newGenerator < GB->size());
-    LowBaseDivisor searchObject(*GB, divisors, maxDivisors, newGenerator);
-    _finder.findAllDivisors(sigNew, searchObject);
+    auto proceed = [&](const Entry& entry) {
+      if (entry.index >= newGenerator)
+        return true;
+      for (size_t j = 0; j <= divisors.size(); ++j) {
+        if (j == divisors.size()) {
+          divisors.push_back(entry.index);
+          break;
+        }
+        int cmp = basis.ratioCompare(entry.index, divisors[j]);
+        if (cmp == EQ && (entry.index < divisors[j]))
+          cmp = GT; // prefer minimum index to ensure deterministic behavior
+        if (cmp == GT) {
+          divisors.insert(divisors.begin() + j, entry.index);
+          break;
+        }
+      }
+      if (divisors.size() > maxDivisors)
+        divisors.pop_back();
+      MATHICGB_ASSERT(divisors.size() <= maxDivisors);
+      return true;
+    };
+    divisors.clear();
+    divisors.reserve(maxDivisors + 1);
+    auto wrap = lambdaWrap(proceed);
+    mLookup.findAllDivisors(basis.getSignature(newGenerator), wrap);
   }
 
   virtual size_t highBaseDivisor(size_t newGenerator) const {
-    const SigPolyBasis* basis = _finder.getConfiguration().sigBasis();
-    MATHICGB_ASSERT(newGenerator < basis->size());
+    const auto& basis = mLookup.getConfiguration().sigBasis();
+    MATHICGB_ASSERT(newGenerator < basis.size());
+    auto highDivisor = size_t(-1);
 
-    HighBaseDivisor searchObject(*basis, newGenerator);
-    _finder.findAllDivisors
-      (basis->getLeadMonomial(newGenerator), searchObject);
-    return searchObject.highDivisor();
+    auto proceed = [&](const Entry& entry) {
+      if (entry.index >= newGenerator)
+        return true;
+      if (highDivisor != size_t(-1)) {
+        int cmp = basis.ratioCompare(highDivisor, entry.index);
+        if (cmp == LT)
+          return true;
+        if (cmp == EQ && (entry.index > highDivisor))
+          return true; // prefer minimum index to ensure deterministic behavior
+      }
+      highDivisor = entry.index;
+      return true;
+    };
+    auto wrap = lambdaWrap(proceed);
+    mLookup.findAllDivisors(basis.getLeadMonomial(newGenerator), wrap);
+    return highDivisor;
   }
 
-  virtual size_t minimalLeadInSig(const_monomial sig) const {
-    MinimalLeadInSig searchObject(*_finder.getConfiguration().sigBasis());
-    _finder.findAllDivisors(sig, searchObject);
+  virtual size_t minimalLeadInSig(ConstMonoRef sig) const {
+    MinimalLeadInSig searchObject(mLookup.getConfiguration().sigBasis());
+    mLookup.findAllDivisors(sig, searchObject);
     return searchObject.minLeadGen();
   }
 
-  virtual size_t classicReducer(const_monomial mon) const {
-    const auto& conf = _finder.getConfiguration();
-    ClassicReducer searchObject(*conf.basis(), conf.preferSparseReducers());
-    _finder.findAllDivisors(mon, searchObject);
+  virtual size_t classicReducer(ConstMonoRef mono) const {
+    const auto& conf = mLookup.getConfiguration();
+    ClassicReducer searchObject(conf.basis(), conf.preferSparseReducers());
+    mLookup.findAllDivisors(mono, searchObject);
     return searchObject.reducer();
   }
 
-  virtual size_t divisor(const_monomial mon) const {
-    const Entry* entry = _finder.findDivisor(mon);
+  virtual size_t divisor(ConstMonoRef mono) const {
+    const Entry* entry = mLookup.findDivisor(mono);
     return entry == 0 ? static_cast<size_t>(-1) : entry->index;
   }
 
-  virtual void divisors(const_monomial mon, EntryOutput& consumer) const {
+  virtual void divisors(ConstMonoRef mono, EntryOutput& consumer) const {
     PassOn out(consumer);
-    _finder.findAllDivisors(mon, out);
+    mLookup.findAllDivisors(mono, out);
   }
 
-  virtual void multiples(const_monomial mon, EntryOutput& consumer) const {
+  virtual void multiples(ConstMonoRef mono, EntryOutput& consumer) const {
     PassOn out(consumer);
-    _finder.findAllMultiples(mon, out);
+    mLookup.findAllMultiples(mono, out);
   }
 
-  virtual void removeMultiples(const_monomial mon) {
-    _finder.removeMultiples(mon);
+  virtual void removeMultiples(ConstMonoRef mono) {
+    mLookup.removeMultiples(mono);
   }
 
-  virtual void remove(const_monomial mon) {
-    _finder.removeElement(mon);
-  }
+  virtual void remove(ConstMonoRef mono) {mLookup.removeElement(mono);}
 
   virtual size_t size() const {
-    return _finder.size();
+    return mLookup.size();
   }
 
-  const C& getConfiguration() const {return _finder.getConfiguration();}
-  C& getConfiguration() {return _finder.getConfiguration();}
+  std::string getName() const {return mLookup.getName();}
+  const PolyRing& ring() const {return mLookup.configuration().ring();}
 
-  std::string getName() const;
-  const PolyRing * getPolyRing() const { return getConfiguration().getPolyRing(); }
-
-  size_t getMemoryUse() const;
+  size_t getMemoryUse() const {return mLookup.getMemoryUse();}
 
 private:
   // Class used in multiples() and divisors()
@@ -239,79 +290,6 @@ private:
     EntryOutput& mOut;
   };
 
-  // Class used in lowBaseDivisor()
-  class LowBaseDivisor {
-  public:
-    LowBaseDivisor(
-      const SigPolyBasis& basis,
-      std::vector<size_t>& divisors,
-      size_t maxDivisors,
-      size_t newGenerator
-    ):
-      mSigBasis(basis),
-      mDivisors(divisors),
-      mMaxDivisors(maxDivisors),
-      mNewGenerator(newGenerator)
-    {
-      mDivisors.clear();
-      mDivisors.reserve(maxDivisors + 1);
-    }
-
-    bool proceed(const Entry& entry) {
-      if (entry.index >= mNewGenerator)
-        return true;
-      for (size_t j = 0; j <= mDivisors.size(); ++j) {
-        if (j == mDivisors.size()) {
-          mDivisors.push_back(entry.index);
-          break;
-        }
-        int cmp = mSigBasis.ratioCompare(entry.index, mDivisors[j]);
-        if (cmp == EQ && (entry.index < mDivisors[j]))
-          cmp = GT; // prefer minimum index to ensure deterministic behavior
-        if (cmp == GT) {
-          mDivisors.insert(mDivisors.begin() + j, entry.index);
-          break;
-        }
-      }
-      if (mDivisors.size() > mMaxDivisors)
-        mDivisors.pop_back();
-      MATHICGB_ASSERT(mDivisors.size() <= mMaxDivisors);
-      return true;
-    }
-  private:
-    const SigPolyBasis& mSigBasis;
-    std::vector<size_t>& mDivisors;
-    const size_t mMaxDivisors;
-    const size_t mNewGenerator;
-  };
-
-  // Class used in highBaseDivisor()
-  class HighBaseDivisor {
-  public:
-    HighBaseDivisor(const SigPolyBasis& basis, size_t newGenerator):
-      mSigBasis(basis),
-      mNewGenerator(newGenerator),
-      mHighDivisor(static_cast<size_t>(-1)) {}
-    bool proceed(const Entry& entry) {
-      if (entry.index >= mNewGenerator)
-        return true;
-      if (mHighDivisor != static_cast<size_t>(-1)) {
-        int cmp = mSigBasis.ratioCompare(mHighDivisor, entry.index);
-        if (cmp == LT)
-          return true;
-        if (cmp == EQ && (entry.index > mHighDivisor))
-          return true; // prefer minimum index to ensure deterministic behavior
-      }
-      mHighDivisor = entry.index;
-      return true;
-    }
-    size_t highDivisor() const {return mHighDivisor;}
-  private:
-    const SigPolyBasis& mSigBasis;
-    const size_t mNewGenerator;
-    size_t mHighDivisor;
-  };
-
   // Class used in minimalLeadInSig()
   class MinimalLeadInSig {
   public:
@@ -349,8 +327,8 @@ private:
             // might be more reduced as the constraint on regular reduction
             // is less. Also, as no two generators have same signature, this
             // ensures deterministic behavior.
-            const const_monomial minSig = mSigBasis.getSignature(mMinLeadGen);
-            const const_monomial genSig = mSigBasis.getSignature(entry.index);
+            const auto minSig = mSigBasis.getSignature(mMinLeadGen);
+            const auto genSig = mSigBasis.getSignature(entry.index);
             int sigCmp = mSigBasis.monoid().compare(minSig, genSig);
             MATHICGB_ASSERT(sigCmp != EQ); // no two generators have same signature
             if (sigCmp == GT)
@@ -411,14 +389,15 @@ private:
   public:
     DOCheckAll(
       const SigPolyBasis& basis,
-      const_monomial sig,
-      const_monomial monom,
+      ConstMonoRef sig,
+      ConstMonoRef monom,
       bool preferSparseReducers
     ):
-      mRatioCmp(sig, monom, basis),
+      mRatioCmp(Monoid::toOld(sig), Monoid::toOld(monom), basis),
       mSigBasis(basis),
       mReducer(static_cast<size_t>(-1)),
-      mPreferSparseReducers(preferSparseReducers) {}
+      mPreferSparseReducers(preferSparseReducers)
+    {}
 
     bool proceed(const Entry& e)
     {
@@ -458,45 +437,20 @@ private:
   };
 
 public:
-  virtual void insert(const_monomial mon, size_t val) {
-        _finder.insert(Entry(mon, val));
+  virtual void insert(ConstMonoRef mono, size_t value) {
+    mLookup.insert(Entry(mono, value));
   }
 
-  virtual size_t regularReducer(const_monomial sig, const_monomial mon) const
-  {
-    DOCheckAll out(
-      *getConfiguration().sigBasis(),
-      sig,
-      mon,
-      getConfiguration().preferSparseReducers()
-    );
-    _finder.findAllDivisors(mon, out);
+  virtual size_t regularReducer(ConstMonoRef sig, ConstMonoRef mono) const {
+    const auto& conf = mLookup.getConfiguration();
+    DOCheckAll out(conf.sigBasis(), sig, mono, conf.preferSparseReducers());
+    mLookup.findAllDivisors(mono, out);
     return out.reducer();
   }
 
-  unsigned long long getExpQueryCount() const {
-    return _finder.getConfiguration().getExpQueryCount();
-  }
-
-  size_t n_elems() const { return _finder.size(); }
-
-  void display(std::ostream &o, int level) const;  /**TODO: WRITE ME */
-  void dump(int level) const; /**TODO: WRITE ME */
- private:
-  Finder _finder;
+private:
+  BaseLookup mLookup;
 };
 
-template<typename C>
-inline std::string DivLookup<C>::getName() const {
-  return "DL " + _finder.getName();
-}
-
-template<typename C>
-size_t DivLookup<C>::getMemoryUse() const
-{
-//#warning "implement getMemoryUse for DivLookup"
-  return 4 * sizeof(void *) * _finder.size();  // NOT CORRECT!!
-}
-
 MATHICGB_NAMESPACE_END
 #endif
diff --git a/src/mathicgb/DivisorLookup.hpp b/src/mathicgb/DivisorLookup.hpp
index 860a41d..fd6c7a2 100755
--- a/src/mathicgb/DivisorLookup.hpp
+++ b/src/mathicgb/DivisorLookup.hpp
@@ -16,6 +16,10 @@ class SigPolyBasis;
 class DivisorLookup
 {
 public:
+  typedef PolyRing::Monoid Monoid;
+  typedef Monoid::ConstMonoRef ConstMonoRef;
+  typedef Monoid::ConstMonoPtr ConstMonoPtr;
+
   // Call after construction. Can be called multiple times, but only if the
   // parameter object is the same each time.
   virtual void setBasis(const PolyBasis& basis) = 0;
@@ -26,19 +30,18 @@ public:
 
   virtual ~DivisorLookup() {}
 
-  virtual void insert(const_monomial mon, size_t index) = 0;
+  virtual void insert(ConstMonoRef mono, size_t index) = 0;
 
-  // Returns the index of a basis element that regular reduces mon in
+  // Returns the index of a basis element that regular reduces mono in
   // signature sig. Returns -1 if no such element exists. A basis element
-  // u is a regular reducer if leadTerm(u) divides mon
-  // and (mon / leadTerm(u)) * signature(u) < sig.
-  virtual size_t regularReducer
-    (const_monomial sig, const_monomial mon) const = 0;
+  // u is a regular reducer if leadTerm(u) divides mono
+  // and (mono / leadTerm(u)) * signature(u) < sig.
+  virtual size_t regularReducer(ConstMonoRef sig, ConstMonoRef mono) const = 0;
 
-  // Returns the index of a basis element whose lead term divides mon. The
+  // Returns the index of a basis element whose lead term divides mono. The
   // strategy used to break ties is up to the implementation of the interface,
   // but the outcome must be deterministic.
-  virtual size_t classicReducer(const_monomial mon) const = 0;
+  virtual size_t classicReducer(ConstMonoRef mono) const = 0;
 
   virtual std::string getName() const = 0;
 
@@ -48,12 +51,13 @@ public:
   virtual void lowBaseDivisors(
     std::vector<size_t>& divisors,
     size_t maxDivisors,
-    size_t newGenerator) const = 0;
-  virtual size_t minimalLeadInSig(const_monomial sig) const = 0;
+    size_t newGenerator
+  ) const = 0;
+  virtual size_t minimalLeadInSig(ConstMonoRef sig) const = 0;
 
   virtual int type() const = 0;
 
-  static void displayDivisorLookupTypes(std::ostream &o);
+  static void displayDivisorLookupTypes(std::ostream& o);
 
   class Factory {
   public:
@@ -71,21 +75,21 @@ public:
   };
 
   // Calls consumer.proceed(index) for each element whose lead term
-  // divides mon. Stops the search if proceed returns false.
-  virtual void multiples(const_monomial mon, EntryOutput& consumer) const = 0;
+  // divides mono. Stops the search if proceed returns false.
+  virtual void multiples(ConstMonoRef mono, EntryOutput& consumer) const = 0;
 
-  // Returns the index of a basis element whose lead term divides mon.
-  virtual size_t divisor(const_monomial mon) const = 0;
+  // Returns the index of a basis element whose lead term divides mono.
+  virtual size_t divisor(ConstMonoRef mono) const = 0;
 
   // Calls consumer.proceed(index) for each element whose term
-  // mon divides. Stops the search if proceed returns false.
-  virtual void divisors(const_monomial mon, EntryOutput& consumer) const = 0;
+  // mono divides. Stops the search if proceed returns false.
+  virtual void divisors(ConstMonoRef mono, EntryOutput& consumer) const = 0;
 
-  // Removes multiples of mon. An element equal to mon counts as a multiple.
-  virtual void removeMultiples(const_monomial mon) = 0;
+  // Removes multiples of mono. An element equal to mono counts as a multiple.
+  virtual void removeMultiples(ConstMonoRef mono) = 0;
 
-  // Removes entries whose monomial are equal to mon.
-  virtual void remove(const_monomial mon) = 0;
+  // Removes entries whose monomial are equal to mono.
+  virtual void remove(ConstMonoRef mono) = 0;
 
   // Returns how many elements are in the data structure.
   virtual size_t size() const = 0;
diff --git a/src/mathicgb/PolyRing.hpp b/src/mathicgb/PolyRing.hpp
index d8d7358..aeee47d 100755
--- a/src/mathicgb/PolyRing.hpp
+++ b/src/mathicgb/PolyRing.hpp
@@ -125,8 +125,12 @@ public:
   exponent component() const { return *mValue; }
 
   operator Monoid::ConstMonoRef() const {
+    MATHICGB_ASSERT(!isNull());
     return Monoid::toRef(mValue);
   }
+  operator Monoid::ConstMonoPtr() const {
+    return Monoid::toRef(mValue).ptr();
+  }
 
 private:
   const exponent& operator[](size_t index) const { return mValue[index]; }
@@ -160,8 +164,12 @@ public:
   exponent const * unsafeGetRepresentation() const { return mValue; }
 
   operator Monoid::MonoRef() {
+    MATHICGB_ASSERT(!isNull());
     return Monoid::toRef(unsafeGetRepresentation());
   }
+  operator Monoid::MonoPtr() {
+    return Monoid::toRef(unsafeGetRepresentation()).ptr();
+  }
 
 private:
   const exponent& operator[](size_t index) const { return mValue[index]; }
diff --git a/src/mathicgb/SPairs.cpp b/src/mathicgb/SPairs.cpp
index 90cc66a..ad57efe 100755
--- a/src/mathicgb/SPairs.cpp
+++ b/src/mathicgb/SPairs.cpp
@@ -395,8 +395,9 @@ bool SPairs::simpleBuchbergerLcmCriterion(
         ++mStats.buchbergerLcmCacheHits;
     } else {
       MATHICGB_ASSERT(!criterion.applies());
+      // This will be a tough nut to crack in terms of getting the types to match.
       mBasis.divisorLookup().divisors
-        (BareMonoid::toOld(criterion.lcmAB()), criterion);
+        (Monoid::toRef(BareMonoid::toOld(criterion.lcmAB())), criterion);
       applies = criterion.applies();
 
       if (mUseBuchbergerLcmHitCache && applies) {
@@ -508,7 +509,8 @@ bool SPairs::advancedBuchbergerLcmCriterion(
   Graph& graph = mAdvancedBuchbergerLcmCriterionGraph;
   graph.clear();
   GraphBuilder builder(graph);
-  mBasis.divisorLookup().divisors(BareMonoid::toOld(lcmAB), builder);
+  // This will be a tough nut to crack in terms of getting the types to match.
+  mBasis.divisorLookup().divisors(Monoid::toRef(BareMonoid::toOld(lcmAB)), builder);
 
   if (graph.size() <= 3) {
     // For the graph approach to be better than the simpler approach of

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