Gröbner basis project
Codebase for research into Gröbner basis computation
algorithm_buchberger_basic.cpp
1 #ifndef __ALGORITHM_BUCHBERGER_BASIC_CPP_
2 #define __ALGORITHM_BUCHBERGER_BASIC_CPP_
3 
4 /*****************************************************************************\
5 * This file is part of DynGB. *
6 * *
7 * DynGB is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * Foobar is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with DynGB. If not, see <http://www.gnu.org/licenses/>. *
19 \*****************************************************************************/
20 
21 #include "algorithm_buchberger_basic.hpp"
22 
23 #include "reduction_support.hpp"
24 
25 bool lcm_alike(const Monomial & t, const Monomial & u,
26  const Critical_Pair_Basic * p)
27 {
28  bool result = true;
29  for (NVAR_TYPE i = 0; result and i < t.num_vars(); ++i)
30  result = result and p->lcm_degree(i) == ((t.degree(i) >= u.degree(i)) ?
31  t.degree(i) : u.degree(i));
32  return result;
33 }
34 
35 list<Abstract_Polynomial *> reduce_basis(list<Abstract_Polynomial *>G) {
36  list <Abstract_Polynomial *> result;
37  set <Abstract_Polynomial *> eliminate; // save polynomials for deletion
38  // we identify polynomials that need deletion, but wait to delete
39  for (Abstract_Polynomial * f : G)
40  {
41  bool eliminated = false;
42  // look for divisors of f in G
43  for (Abstract_Polynomial * g : G) {
44  if (g != f and g->leading_monomial() | f->leading_monomial()) {
45  eliminated = true;
46  eliminate.insert(f);
47  break;
48  }
49  }
50  // look for divisors of f in result
51  if (not eliminated)
52  for (Abstract_Polynomial * g : result) {
53  if (g != f and g->leading_monomial() | f->leading_monomial()) {
54  eliminated = true;
55  eliminate.insert(f);
56  break;
57  }
58  }
59  if (not eliminated) {
60  result.push_back(f);
61  }
62  }
63  // eliminate the eliminated
64  for (Abstract_Polynomial * g : eliminate)
65  delete g;
66  return result;
67 }
68 
69 void check_correctness(list<Constant_Polynomial *>G, StrategyFlags strategy) {
70  cout << "quick check for correctness\n";
71  for (auto fi = G.begin(); fi != G.end(); ++fi)
72  for (auto gi = next(fi); gi != G.end(); ++gi)
73  {
74  Critical_Pair_Basic * p = new Critical_Pair_Basic(*fi, *gi, strategy);
76  SPolyCreationFlags::LINKED_LST, strategy
77  );
78  reduce_over_basis<list<Constant_Polynomial *>>(&s, G);
79  if (not s->is_zero())
80  cout << "\tfailure with " << p->first()->leading_monomial() << ','
81  << p->second()->leading_monomial() << ':' << s->leading_monomial()
82  << endl;
83  delete s;
84  }
85 }
86 
87 void gm_update(
88  list<Critical_Pair_Basic *> & P,
89  list<Abstract_Polynomial *> & G,
91  StrategyFlags strategy
92 ) {
93  //cout << "----------------------\n";
94  list<Critical_Pair_Basic *> C;
95  // critical pairs with new polynomial
96  for (Abstract_Polynomial * g : G)
97  C.push_back(new Critical_Pair_Basic(g, r, strategy));
98  // apply Buchberger's lcm criterion to new pairs
99  list<Critical_Pair_Basic *> D;
100  while (C.size() != 0) {
101  Critical_Pair_Basic * p = C.front();
102  C.pop_front();
103  if ((p->first()->leading_monomial().is_coprime(
104  p->second()->leading_monomial()))
105  or (no_triplet(p, C) and no_triplet(p, D))
106  )
107  D.push_back(p);
108  else {
109  delete p;
110  //cout << "triplet prunes " << *p << endl;
111  }
112  }
113  // apply Buchberger's gcd criterion
114  list<Critical_Pair_Basic *> E;
115  while (D.size() != 0) {
116  Critical_Pair_Basic * p = D.front();
117  D.pop_front();
118  if (!(p->first()->leading_monomial().is_coprime(
119  p->second()->leading_monomial())))
120  E.push_back(p);
121  else {
122  delete p;
123  // cout << "gcd prunes " << *p << endl;
124  }
125  }
126  // apply Buchberger's lcm criterion to old pairs
127  list<Critical_Pair_Basic *> Q;
128  while (P.size() != 0) {
129  Critical_Pair_Basic * p = P.front();
130  P.pop_front();
131  bool crit1 = !(r->leading_monomial() | p->lcm());
132  bool crit2 = lcm_alike(p->first()->leading_monomial(), r->leading_monomial(), p);
133  bool crit3 = p->second() != nullptr and
135  if ( crit1 or crit2 or crit3)
136  Q.push_back(p);
137  else {
138  if (p->s_polynomial() != nullptr) delete p->s_polynomial();
139  delete p;
140  //cout << "triplet prunes " << *p << endl;
141  }
142  }
143  P = Q;
144  // add new pairs to old pairs
145  for (Critical_Pair_Basic * e : E)
146  P.push_back(e);
147  /*cout << "All pairs:\n";
148  for (auto pi = P.begin(); pi != P.end(); ++pi)
149  cout << '\t' << **pi << endl;
150  cout << "----------------------\n";*/
151  // add new poly to basis
152  G.push_back(r);
153 }
154 
155 void report_basis(
156  list<Abstract_Polynomial *> G,
157  bool verbose,
158  bool very_verbose
159 ) {
160  cout << G.size() << " polys in basis\n";
161  if (verbose) {
162  for (Abstract_Polynomial * g : G) cout << g->leading_monomial() << '\t';
163  cout << endl;
164  }
165  if (very_verbose) {
166  for (Abstract_Polynomial * g : G) g->println();
167  }
168 }
169 
170 void report_front_pair(Critical_Pair_Basic *p, StrategyFlags strategy) {
171  cout << "processing pair: " << *p << endl;
172  if (
173  strategy == StrategyFlags::SUGAR_STRATEGY or
174  strategy == StrategyFlags::WSUGAR_STRATEGY
175  ) {
176  cout << "\tsugar: "
177  << ((Pair_Sugar_Data *)(p->pair_key()))->pair_sugar() << endl;
178  }
179 }
180 
181 list<Constant_Polynomial *> buchberger(
182  const list<Abstract_Polynomial *> &F,
183  SPolyCreationFlags method,
184  StrategyFlags strategy,
185  WT_TYPE * strategy_weights
186 ) {
187  unsigned number_of_spolys = 0;
188  list<Abstract_Polynomial *> G;
189  list<Critical_Pair_Basic *> P;
190  // set up basis with generators
191  for (Abstract_Polynomial * fo : F)
192  {
194  switch(strategy) {
195  case StrategyFlags::NORMAL_STRATEGY: break; // don't need polynomial data
196  case StrategyFlags::SUGAR_STRATEGY:
197  f->set_strategy(new Poly_Sugar_Data(f));
198  break;
199  case StrategyFlags::WSUGAR_STRATEGY:
200  f->set_strategy(new Poly_WSugar_Data(f, strategy_weights));
201  break;
202  default: break; // assume normal strategy
203  }
204  if (f->strategy() != nullptr) { f->strategy()->at_generation_tasks(); }
205  P.push_back(new Critical_Pair_Basic(f, strategy));
206  }
207  // main loop
208  bool verbose = false;
209  bool very_verbose = false;
210  while (!P.empty()) {
213  Critical_Pair_Basic * p = P.front();
214  report_front_pair(p, strategy);
215  P.pop_front();
216  // make s-poly
217  Mutable_Polynomial * s = p->s_polynomial(method, strategy);
218  ++number_of_spolys;
219  if (p->is_generator())
220  delete p->first();
221  delete p;
222  // cout << "Reducing s-poly "; s->println();
223  if (!s->is_zero())
224  reduce_over_basis<list<Abstract_Polynomial *>>(&s, G);
225  if (s->is_zero()) {
226  cout << "\treduced to zero\n";
227  delete s;
228  } else {
230  r = new Constant_Polynomial(*s);
231  // move strategy from s to r
232  r->set_strategy(s->strategy());
233  s->set_strategy(nullptr);
234  delete s;
235  cout << "\tadded " << r->leading_monomial() << endl;
236  if (very_verbose) { cout << "\tadded "; r->println(); }
237  gm_update(P, G, r, strategy);
238  }
239  }
240  cout << number_of_spolys << " s-polynomials computed and reduced\n";
241  // cleanup
242  cout << G.size() << " polynomials before interreduction\n";
243  //check_correctness(G, strategy);
244  G = reduce_basis(G);
245  cout << G.size() << " polynomials after interreduction\n";
246  //set<Constant_Polynomial *, smaller_lm> B;
247  list<Constant_Polynomial *> B;
248  unsigned long num_mons = 0;
249  unsigned long max_mons = 0;
250  for (Abstract_Polynomial * g : G) {
251  unsigned long glen = g->length();
252  num_mons += glen;
253  if (glen > max_mons) max_mons = glen;
254  B.push_back(new Constant_Polynomial(*g));
255  }
256  cout << "tot # monomials: " << num_mons;
257  cout << "max # monomials: " << max_mons;
258  cout << "avg # monomials: " << num_mons / B.size() << endl;
259  return B;
260 }
261 
262 #endif
The general class of a polynomial.
Definition: polynomial.hpp:101
virtual bool is_zero() const =0
is this polynomial zero?
A Constant_Polynomial is a polynomial that should not change.
void sort_pairs_by_strategy(list< T *> &P)
Applies the strategy to find the “smallest” critical pair.
const Abstract_Polynomial * second() const
second polynomial in pair
void gm_update(list< Critical_Pair_Basic *> &P, list< Abstract_Polynomial *> &G, Abstract_Polynomial *r, StrategyFlags strategy)
Implementation of Gebauer-Moeller algorithm. Based on description in Becker and Weispfenning (1993)...
list< Constant_Polynomial * > buchberger(const list< Abstract_Polynomial *> &F, SPolyCreationFlags method, StrategyFlags strategy, WT_TYPE *strategy_weights)
Implementation of Buchberger’s algorithm.
virtual Monomial & leading_monomial() const =0
leading monomial – call after sort_by_order()!
const Monomial & lcm() const
lcm of leading monomials of polynomials
ordering critical pairs using the sugar strategy
void reduce_over_basis(Mutable_Polynomial **sp, const T &G, int comm_id=0)
Reduce the polynomial r over the basis G.
virtual void at_generation_tasks()
hook called while first generating polynomial
Definition: strategies.hpp:88
StrategyFlags
flag indicating which strategy to use for computation
Definition: strategies.hpp:34
list< Abstract_Polynomial * > reduce_basis(list< Abstract_Polynomial *>G)
Remove redundant polynomials from G.
SPolyCreationFlags
flag indicating which structure to use for an s-polynomial
bool lcm_alike(const Monomial &t, const Monomial &u, const Critical_Pair_Basic *p)
Checks if the lcm of t and u is like the lcm stored in p.
NVAR_TYPE num_vars() const
number of variables
Definition: monomial.hpp:130
Polynomials that need arithmetic typically descend from this class.
Definition: polynomial.hpp:305
const Abstract_Polynomial * first() const
first polynomial in pair
polynomial-related data for a weighted sugar strategy
Implementation of monomials.
Definition: monomial.hpp:69
void check_correctness(list< Constant_Polynomial *>G, StrategyFlags strategy)
checks that G is a Gröbner basis by verifying each s-polynomial reduces to zero
polynomial-related data for a sugar strategy
virtual Mutable_Polynomial * s_polynomial()
to use only if s-polynomial is already computed by another method
bool is_coprime(const Monomial &other) const
true iff this has no common factor with other.
Definition: monomial.cpp:243
DEG_TYPE degree(NVAR_TYPE i) const
Degree of th variable.
Definition: monomial.cpp:183
unsigned lcm_degree(unsigned i) const
degree of ith variable in lcm
void set_strategy(Poly_Strategy_Data *psd)
sets the polynomial’s strategy to psd
Definition: polynomial.cpp:36
const Pair_Strategy_Data * pair_key() const
strategy used for comparison of pairs
bool no_triplet(const T *p, const list< T *>C)
Checks whether p is in danger of forming a Buchberger triple with some pair listed in C...
Controls the creation of s-polynomials.
void report_critical_pairs(const list< T *>P, bool verbose=false)
A brief report on the number of critical pairs. If verbose is true, also lists them.
bool is_generator() const
whether this pair is from a generator
virtual Poly_Strategy_Data * strategy() const
strategy related information
Definition: polynomial.hpp:144