Gröbner basis project
Codebase for research into Gröbner basis computation
f4_reduction_old.cpp
1 #ifndef __F4_REDUCTION_CPP__
2 #define __F4_REDUCTION_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 "f4_reduction.hpp"
22 #include "algorithm_buchberger_basic.hpp"
23 
24 F4_Reduction_Data::F4_Reduction_Data(
25  const list<Critical_Pair_Basic *> & P,
26  const list<Abstract_Polynomial *> & B
27 ) : G(B) {
28  head = len = 0;
29  A = nullptr;
30  mord = P.front()->first()->monomial_ordering();
31  M_build = new list<Monomial *>();
32  R_build = new list<Abstract_Polynomial *>();
33  for (auto p : P) {
34  strategies.push_back(new Poly_Sugar_Data(p->first()));
35  if (strategies.back() != nullptr) {
36  strategies.back()->at_generation_tasks(p->first_multiplier());
37  if (p->second() != nullptr)
38  strategies.back()->pre_reduction_tasks(p->second_multiplier(), *(p->second()));
39  }
40  auto ri = R_build->begin();
41  add_monomials(nullptr, ri, p->first(), &p->first_multiplier());
42  auto mi = M_build->begin();
43  if (p->second() != nullptr) {
44  *ri = const_cast<Abstract_Polynomial *>(p->second());
45  add_monomials(&mi, ri, p->second());
46  ++ri; ++mi;
47  }
48  }
49  // for each monomial, find an appropriate reducer
50  auto mi = M_build->begin();
51  auto ri = R_build->begin();
52  for (/* */; mi != M_build->end(); ++mi, ++ri) {
53  auto g = G.begin();
54  bool found = ((*ri) != nullptr);
55  while (not found and g != G.end()) {
56  if ((**mi).divisible_by((*g)->leading_monomial())) {
57  found = true;
58  *ri = *g;
59  add_monomials(&mi, ri, *g);
60  g = G.end();
61  }
62  ++g;
63  }
64  }
65  initialize_many(P);
66 }
67 
68 F4_Reduction_Data::F4_Reduction_Data(
70  list<Abstract_Polynomial *> & B
71 ) : G(B) {
72  head = len = 0;
73  A = nullptr;
74  switch(p.first()->strategy()->type()) {
75  case StrategyFlags::NORMAL_STRATEGY: break; /* nothing to do */
76  case StrategyFlags::SUGAR_STRATEGY :
77  strategy = new Poly_Sugar_Data(p.first());
78  break;
79  case StrategyFlags::WSUGAR_STRATEGY: {
80  Poly_WSugar_Data * sd
81  = static_cast<Poly_WSugar_Data *>(p.first()->strategy());
82  const WT_TYPE * w;
83  if (sd == nullptr) w = nullptr;
84  else
85  w = (static_cast<const Weighted_Ordering *>(
86  p.first()->monomial_ordering())
87  )->order_weights();
88  strategy = new Poly_WSugar_Data(p.first(), w);
89  break;
90  }
91  default: break; /* default to normal strategy */
92  }
93  if (strategy != nullptr) {
95  if (p.second() != nullptr)
96  strategy->pre_reduction_tasks(p.second_multiplier(), *(p.second()));
97  }
98  mord = p.first()->monomial_ordering();
99  M_build = new list<Monomial *>();
100  R_build = new list<Abstract_Polynomial *>();
101  // add monomials of first
102  auto ri = R_build->begin();
103  add_monomials(nullptr, ri, p.first(), &p.first_multiplier());
104  auto mi = M_build->begin();
105  if (p.second() != nullptr) {
106  *ri = const_cast<Abstract_Polynomial *>(p.second());
107  add_monomials(&mi, ri, p.second());
108  ++ri; ++mi;
109  }
110  // for each monomial, find an appropriate reducer
111  for ( /* already initialized */ ; mi != M_build->end(); ++mi, ++ri) {
112  auto g = G.begin();
113  bool found = ((*ri) != nullptr);
114  while (not found and g != G.end()) {
115  if ((**mi).divisible_by((*g)->leading_monomial())) {
116  found = true;
117  *ri = *g;
118  add_monomials(&mi, ri, *g);
119  g = G.end();
120  }
121  ++g;
122  }
123  }
124  initialize(const_cast<Abstract_Polynomial *>(p.first()), p.first_multiplier());
125 }
126 
127 void F4_Reduction_Data::initialize_many(const list<Critical_Pair_Basic *> & P) {
128  len = M_build->size();
129  Abstract_Polynomial * p = const_cast<Abstract_Polynomial *>(P.front()->first());
130  Prime_Field & F = const_cast<Prime_Field &>(p->ground_field());
131  head = 0;
132  M = new Monomial *[len] { nullptr };
133  A = (Prime_Field_Element *)malloc(sizeof(Prime_Field_Element)*len*P.size());
134  for (unsigned i = 0; i < len; ++i)
135  A[i].assign(0, &F);
136  auto mi = M_build->begin();
137  for (unsigned i = 0; i < len; ++i)
138  M[i] = *mi;
139  // TODO: Populate the matrix in parallel
140  unsigned row = 0;
141  for (auto cp : P) {
142  auto p = cp->first();
143  auto t = cp->first_multiplier();
144  auto pi = p->new_iterator();
145  nonzero_entries = 0;
146  mi = M_build->begin();
147  for (unsigned i = 0; i < len; ++i) {
148  if ((not pi->fellOff()) and M[i]->like_multiple(pi->currMonomial(), t)) {
149  *(A + row*len + i) = pi->currCoeff();
150  pi->moveRight();
151  ++nonzero_entries;
152  }
153  }
154  ++row;
155  delete pi;
156  }
157  R.resize(R_build->size());
158  unsigned i = 0;
159  for (Abstract_Polynomial * r : *R_build)
160  R[i++] = r;
161  delete M_build;
162  delete R_build;
163  Rx = &(P.front()->first()->base_ring());
164 }
165 
167  len = M_build->size();
168  Prime_Field & F = p->ground_field();
169  head = 0;
170  M = new Monomial *[len] { nullptr };
171  A = (Prime_Field_Element *)malloc(sizeof(Prime_Field_Element)*len);
172  for (unsigned i = 0; i < len; ++i) {
173  A[i].assign(0, &F);
174  }
175  Polynomial_Iterator * pi = p->new_iterator();
176  auto mi = M_build->begin();
177  nonzero_entries = 0;
178  for (unsigned i = 0; i < len; ++i) {
179  M[i] = *mi;
180  if ((not pi->fellOff()) and (**mi).like_multiple(pi->currMonomial(), t)) {
181  A[i] = pi->currCoeff();
182  pi->moveRight();
183  ++nonzero_entries;
184  }
185  ++mi;
186  }
187  R.resize(R_build->size());
188  unsigned i = 0;
189  for (Abstract_Polynomial * r : *R_build)
190  R[i++] = r;
191  delete pi;
192  delete M_build;
193  delete R_build;
194  Rx = &(p->base_ring());
195 }
196 
198  list<Monomial *>::iterator * ti,
199  list<Abstract_Polynomial *>::iterator & rp,
200  const Abstract_Polynomial *g,
201  const Monomial * u
202 ) {
203  NVAR_TYPE n = g->leading_monomial().num_vars();
204  if (ti == nullptr) { // g is a generator
205  Polynomial_Iterator * pi = g->new_iterator();
206  while (not (pi->fellOff())) {
207  Monomial * t = new Monomial(pi->currMonomial());
208  (*t) *= (*u);
209  M_build->push_back(t);
210  R_build->push_back(nullptr);
211  pi->moveRight();
212  }
213  delete pi;
214  rp = R_build->begin();
215  } else { // g is not a generator; advance and compare while inserting
216  auto ri(rp);
217  auto tp = *ti;
218  Monomial * v = new Monomial(**tp);
219  (*v) /= g->leading_monomial();
220  ++tp; ++ri;
221  Polynomial_Iterator * pi = g->new_iterator(); pi->moveRight();
222  while (not (pi->fellOff())) {
223  Monomial * t = new Monomial(pi->currMonomial());
224  (*t) *= (*v);
225  while (tp != M_build->end() and *t < **tp) {
226  ++tp; ++ri;
227  }
228  if (tp == M_build->end()) {
229  M_build->push_back(t);
230  R_build->push_back(nullptr);
231  } else if (*t == **tp)
232  delete t;
233  else {
234  M_build->insert(tp, t);
235  R_build->insert(ri, nullptr);
236  }
237  pi->moveRight();
238  }
239  delete pi;
240  }
241 }
242 
243 F4_Reduction_Data::~F4_Reduction_Data() {
244  for (unsigned i = 0; i < len; ++i)
245  delete M[i];
246  delete [] M;
247  free(A);
248  if (strategy != nullptr) delete strategy;
249 }
250 
251 void F4_Reduction_Data::list_reducers() {
252  for (unsigned i = 0; i < len; ++i) {
253  cout << *(M[i]) << " to be reduced by ";
254  if (R[i] == nullptr)
255  cout << "none\n";
256  else
257  cout << R[i]->leading_monomial() << endl;
258  }
259 }
260 
262  return nonzero_entries == 0;
263 }
264 
266  Constant_Polynomial * result;
267  if (nonzero_entries == 0)
268  result = nullptr;
269  else {
270  NVAR_TYPE n = M[0]->num_vars();
271  Monomial * M_final = (Monomial *)malloc(sizeof(Monomial)*nonzero_entries);
272  Prime_Field_Element * A_final
274  unsigned i = 0;
275  Prime_Field_Element scale(A[head].inverse(), A[head].field());
276  for (unsigned j = head; j < len; ++j) {
277  if (not A[j].is_zero()) {
278  A_final[i] = A[j]*scale;
279  M_final[i].common_initialization();
280  M_final[i].initialize_exponents(n);
281  M_final[i].set_monomial_ordering(mord);
282  M_final[i] = *M[j];
283  ++i;
284  }
285  }
286  result = new Constant_Polynomial(
288  *Rx,
289  M_final, A_final,
290  mord
291  );
292  free(M_final);
293  free(A_final);
294  }
295  return result;
296 }
297 
299  NVAR_TYPE n = M[0]->num_vars();
300  EXP_TYPE * u = new EXP_TYPE[n]; // exponents of multiplier
301  // loop through our terms
302  for (unsigned i = head; i < len; ++i) {
303  //u /= u;
304  // do we need to reduce this term, and can we?
305  if ((not A[i].is_zero()) and R[i] != nullptr) {
306  // get reducer for this monomial
307  const Abstract_Polynomial * g = R[i];
308  Polynomial_Iterator * gi = g->new_iterator();
309  // determine multiplier
310  for (NVAR_TYPE k = 0; k < n; ++k) {
311  u[k] = (*M[i])[k] - (gi->currMonomial())[k];
312  }
313  // determine reduction coefficient
314  Prime_Field_Element a(A[i]*gi->currCoeff().inverse());
315  // loop through g's terms
316  // by construction, monomials of u*g[i] should already appear in M,
317  // so the line marked *** SHOULD NOT need a guard
318  unsigned j = i;
319  while (not gi->fellOff()) {
320  const Monomial & t = gi->currMonomial();
321  while (not M[j]->like_multiple(u, t)) ++j;
322  bool was_zero = A[j].is_zero();
323  A[j] -= a*gi->currCoeff();
324  if (was_zero and not A[j].is_zero())
325  ++nonzero_entries;
326  else if (not was_zero and A[j].is_zero())
327  --nonzero_entries;
328  ++j;
329  gi->moveRight();
330  }
331  if (strategy != nullptr)
332  strategy->pre_reduction_tasks(u, *g);
333  advance_head();
334  delete gi;
335  }
336  }
337  delete [] u;
338 }
339 
340 list<Constant_Polynomial *> f4_control(
341  const list<Abstract_Polynomial *> &F,
342  SPolyCreationFlags method,
344  WT_TYPE * strategy_weights
345 ) {
346  unsigned number_of_spolys = 0;
347  list<Abstract_Polynomial *> G;
348  list<Critical_Pair_Basic *> P;
349  // set up basis with generators
350  for (Abstract_Polynomial * fo : F)
351  {
353  switch(strategy) {
354  case StrategyFlags::NORMAL_STRATEGY: break; // don't need polynomial data
355  case StrategyFlags::SUGAR_STRATEGY:
356  f->set_strategy(new Poly_Sugar_Data(f));
357  break;
358  case StrategyFlags::WSUGAR_STRATEGY:
359  f->set_strategy(new Poly_WSugar_Data(f, strategy_weights));
360  break;
361  default: break; // assume normal strategy
362  }
363  if (f->strategy() != nullptr) { f->strategy()->at_generation_tasks(); }
364  P.push_back(new Critical_Pair_Basic(f, strategy));
365  }
366  // main loop
367  bool verbose = false;
368  bool very_verbose = false;
369  while (!P.empty()) {
372  Critical_Pair_Basic * p = P.front();
373  report_front_pair(p, strategy);
374  P.pop_front();
375  // make s-poly
376  //Mutable_Polynomial * s = p->s_polynomial(method, strategy);
377  F4_Reduction_Data s(*p, G);
378  //s.list_reducers();
379  ++number_of_spolys;
380  // cout << "Reducing s-poly "; s->println();
381  if (not s.is_zero())
382  s.reduce();
383  if (s.is_zero()) {
384  cout << "\treduced to zero\n";
385  // delete s;
386  } else {
387  Abstract_Polynomial * r = s.finalize();
388  // move strategy from s to r
389  r->set_strategy(s.get_strategy());
390  s.clear_strategy();
391  //delete s;
392  cout << "\tadded " << r->leading_monomial() << endl;
393  if (very_verbose) { cout << "\tadded "; r->println(); }
394  gm_update(P, G, r, strategy);
395  }
396  if (p->is_generator())
397  delete p->first();
398  delete p;
399  }
400  cout << number_of_spolys << " s-polynomials computed and reduced\n";
401  // cleanup
402  cout << G.size() << " polynomials before interreduction\n";
403  //check_correctness(G, strategy);
404  G = reduce_basis(G);
405  cout << G.size() << " polynomials after interreduction\n";
406  list<Constant_Polynomial *> B;
407  for (Abstract_Polynomial * g : G) {
408  B.push_back(new Constant_Polynomial(*g));
409  //if (F.find(g) == F.end()) delete g;
410  }
411  return B;
412 }
413 
414 #endif
void advance_head()
advances head; useful after a computation
The general class of a polynomial.
Definition: polynomial.hpp:101
const Monomial & second_multiplier() const
monomial needed to multiply second polynomial to lcm()
const Monomial_Ordering * monomial_ordering() const
reports leading monomial’s monomial ordering
Definition: polynomial.hpp:130
Poly_Strategy_Data * get_strategy()
returns the strategy currently in use
A Constant_Polynomial is a polynomial that should not change.
bool is_zero()
returns true iff all the entries are 0
vector< Abstract_Polynomial * > R
finalized list of indices of reducers for the corresponding monomials of f
unsigned len
length of the polynomial
void sort_pairs_by_strategy(list< T *> &P)
Applies the strategy to find the “smallest” critical pair.
virtual Polynomial_Iterator * new_iterator() const =0
An iterator that poses no risk of modifying the polynomial.
virtual void moveRight()=0
Moves right in the polynomial, to the next smaller monomial.
bool is_zero() const
Is this the additive identity?
Definition: fields.hpp:180
vector< Monomial * > M
monomials for each column
const Abstract_Polynomial * second() const
second polynomial in pair
virtual const Prime_Field_Element & currCoeff() const =0
Reports the coefficient at the current position.
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)...
vector< Constant_Polynomial * > finalize()
converts this to a Constant_Polynomial and returns the result
Information necessary for a field modulo a prime.
Definition: fields.hpp:49
void set_monomial_ordering(const Monomial_Ordering *mord)
sets the Monomial_Ordering associated with this Monomial
Definition: monomial.cpp:211
virtual Monomial & leading_monomial() const =0
leading monomial – call after sort_by_order()!
Prime_Field & ground_field()
ground field – all coefficients should be in this field
Definition: polynomial.cpp:27
list< Abstract_Polynomial * > R_build
indices of reducers for the corresponding elements of M
void clear_strategy(unsigned i)
clears the strategy; do this if you have saved it elsewhere
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
void reduce()
reduces polynomial
NVAR_TYPE num_vars() const
number of variables
Definition: monomial.hpp:130
void initialize(Abstract_Polynomial *p, const Monomial &t)
copy temporary to permanent reducers; free list of monomials; insert p&#39;s coefficients, aligned with multiples of t
virtual bool fellOff() const =0
const Abstract_Polynomial * first() const
first polynomial in pair
polynomial-related data for a weighted sugar strategy
Implementation of monomials.
Definition: monomial.hpp:69
Element of a field of prime characteristic.
Definition: fields.hpp:137
Poly_Strategy_Data * strategy
strategy in use
polynomial-related data for a sugar strategy
list< Constant_Polynomial * > f4_control(const list< Abstract_Polynomial *> &F, SPolyCreationFlags method, StrategyFlags strategy, WT_TYPE *strategy_weights)
equivalent to buchberger(), but for Faugère’s F4 algorithm
vector< Poly_Sugar_Data * > strategies
strategy data for each polynomial
const Monomial & first_multiplier() const
monomial needed to multiply first polynomial to lcm()
const Monomial_Ordering * mord
how the monomials are ordered
void initialize_exponents(NVAR_TYPE number_of_vars)
allocates memory for exponents This is useful when you want to allocate an array of monomials...
Definition: monomial.cpp:65
interface to a weighted monomial ordering
void set_strategy(Poly_Strategy_Data *psd)
sets the polynomial’s strategy to psd
Definition: polynomial.cpp:36
void add_monomials(list< Monomial *>::iterator &ti, list< Abstract_Polynomial *>::iterator &ri, const Abstract_Polynomial *g, const Monomial &u, bool new_row=false)
adds monomials of to M_build
Used to iterate through a polynomial.
Definition: polynomial.hpp:224
COEF_TYPE inverse() const
Returns the multiplicative inverse of this.
Definition: fields.cpp:83
virtual const Monomial & currMonomial() const =0
Reports the monomial at the current position.
unsigned head
head of the polynomial (location of leading term)
vector< unsigned > nonzero_entries
number of nonzero entries of each row of A
Implementation of Faugère’s F4 algorithm.
Controls the creation of s-polynomials.
Prime_Field_Element * A
coefficient data
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.
list< Monomial * > M_build
monomials while building
Polynomial_Ring & Rx
polynomial ring
bool is_generator() const
whether this pair is from a generator
void assign(COEF_TYPE val, Prime_Field *K)
for initializing arrays of Prime_Field_Element
Definition: fields.hpp:187
Polynomial_Ring & base_ring() const
ring in which this polynomial resides
Definition: polynomial.cpp:25
void common_initialization(const Monomial_Ordering *ord=nullptr)
things all Monomial initializers must do
Definition: monomial.hpp:74
const list< Abstract_Polynomial * > & G
current basis of ideal
virtual Poly_Strategy_Data * strategy() const
strategy related information
Definition: polynomial.hpp:144