Gröbner basis project
Codebase for research into Gröbner basis computation
polynomial_geobucket.cpp
1 #ifndef __POLYNOMIAL_GEOBUCKET_CPP_
2 #define __POLYNOMIAL_GEOBUCKET_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 "polynomial_geobucket.hpp"
22 
24  return pi != nullptr and pi->canMoveLeft();
25 }
26 
28  return pi != nullptr and pi->canMoveRight();
29 }
30 
32  return pi == nullptr or pi->fellOff();
33 }
34 
36  return pi->currMonomial();
37 }
38 
40  return pi->currCoeff();
41 }
42 
44 {
45  pi->set_currCoeff(a);
46 }
47 
49  pi->set_currMonomial(t);
50 }
51 
53  return new Geobucket_Iterator(this);
54 }
55 
56 Polynomial_Iterator * Polynomial_Geobucket::begin() const {
57  return new Geobucket_Iterator(this);
58 }
59 
60 Polynomial_Iterator * Polynomial_Geobucket::end() const {
61  return new Geobucket_Iterator(this, true);
62 }
63 
65  return new Geobucket_Iterator(this);
66 }
67 
68 Geobucket_Iterator::Geobucket_Iterator(
69  const Polynomial_Geobucket * poly, bool at_end
70 ) {
71  p = g = const_cast<Polynomial_Geobucket *>(poly);
72  bucket_number = 0;
73  if (at_end)
74  for (unsigned i = 0; i < NUM_BUCKETS; ++i)
75  if (poly->buckets[i] != nullptr)
76  bucket_number = i;
78 }
79 
80 Geobucket_Iterator::Geobucket_Iterator(Polynomial_Geobucket * poly, bool at_end)
81 {
82  p = g = poly;
83  bucket_number = 0;
84  if (at_end)
85  for (unsigned i = 0; i < NUM_BUCKETS; ++i)
86  if (poly->buckets[i] != nullptr)
87  bucket_number = i;
89 }
90 
91 Geobucket_Iterator::~Geobucket_Iterator() {
92  delete pi;
93 }
94 
96  if (bucket_number != 0) {
97  delete pi;
98  bucket_number = 0;
99  pi = new LLPolynomial_Iterator(g->buckets[0]);
100  }
101 }
102 
104  if (pi != nullptr) {
105  pi->moveRight();
106  if (pi->fellOff()) {
107  delete pi;
108  pi = nullptr;
109  do
110  ++bucket_number;
111  while (bucket_number < NUM_BUCKETS
112  and g->buckets[bucket_number] == nullptr);
113  if (bucket_number < NUM_BUCKETS and g->buckets[bucket_number] != nullptr)
115  }
116  }
117 }
118 
120  if (pi != nullptr) {
121  pi->moveLeft();
122  if (pi->fellOff()) {
123  delete pi;
124  pi = nullptr;
125  // unlike moving right, we can always fall back on buckets[0]
126  do
127  --bucket_number;
128  while (g->buckets[bucket_number] == nullptr);
130  }
131  }
132 }
133 
136 ) : Mutable_Polynomial(R, order) {
137  // I don't expect to need NUM_BUCKETS, but the mere pointers to potential
138  // buckets can't be entirely bad (I hope...)
139  buckets = (Polynomial_Linked_List **)malloc(
140  NUM_BUCKETS*sizeof(Polynomial_Linked_List *));
141  buckets[0] = new Polynomial_Linked_List(R, order);
142  for (unsigned i = 1; i < NUM_BUCKETS; ++i)
143  buckets[i] = nullptr;
144 }
145 
148 {
149  unsigned n = p.number_of_variables();
150  buckets = (Polynomial_Linked_List **)malloc(
151  NUM_BUCKETS*sizeof(Polynomial_Linked_List *));
152  for (unsigned i = 1; i < NUM_BUCKETS; ++i)
153  buckets[i] = nullptr;
154  unsigned i = lglen(p.length());
155  buckets[i] = new Polynomial_Linked_List(p);
156  if (i > 0) {
157  buckets[0] = buckets[i]->detach_head();
158  }
159 }
160 
162  for (unsigned i = 0; i < NUM_BUCKETS; ++i)
163  if (buckets[i] != nullptr)
164  delete buckets[i];
165  free(buckets);
166 }
167 
169 {
170  for (unsigned i = 0; i < NUM_BUCKETS; ++i)
171  buckets[i]->sort_by_order();
172 }
173 
175  const Monomial_Ordering * order, bool sort_anew
176 ) {
177  for (unsigned i = 0; i < NUM_BUCKETS; ++i)
178  buckets[i]->set_monomial_ordering(order, sort_anew);
179 }
180 
182  return buckets[0]->leading_monomial();
183 }
184 
186  return buckets[0]->leading_coefficient();
187 }
188 
190  unsigned result = 0;
191  for (unsigned i = 0; i < NUM_BUCKETS; ++i)
192  if (buckets[i] != 0)
193  result += buckets[i]->length();
194  return result;
195 }
196 
198  return new Polynomial_Linked_List(R);
199 }
200 
202  unsigned result = true;
203  for (unsigned i = 0; result and i < NUM_BUCKETS; ++i)
204  result = buckets[i] == nullptr or buckets[i]->is_zero();
205  return result;
206 }
207 
209  // I'm not sure why you'd want to do this,
210  // but we need it for class consistency.
211  return leading_monomial() | other.leading_monomial();
212 }
213 
215  unsigned i = 0;
216  do {
217  i = 0;
218  for (unsigned j = 1; j < NUM_BUCKETS; ++j)
219  if (i != j and buckets[j] != nullptr and (not buckets[j]->is_zero())) {
220  if (buckets[i]->is_zero() or
222  i = j;
223  else {
224  if (buckets[i]->leading_monomial().is_like(
225  buckets[j]->leading_monomial())) {
227  *buckets[i] += *q;
228  delete q;
229  j = 0; // need to restart from bucket 1
230  if (buckets[i]->is_zero()) {
231  delete buckets[i];
232  buckets[i] = nullptr;
233  i = 0;
234  }
235  }
236  }
237  }
238  } while (i != 0 and buckets[i]->is_zero());
239  if (i == 0)
240  delete buckets[0]->detach_head();
241  else {
242  if (buckets[0] != nullptr)
243  delete buckets[0];
244  buckets[0] = buckets[i]->detach_head();
245  }
246 }
247 
250  for (unsigned i = 0; i < NUM_BUCKETS; ++i)
251  if (buckets[i] != nullptr)
252  result->buckets[i] = buckets[i]->monomial_multiple(t);
253  return result;
254 }
255 
257 const {
259  for (unsigned i = 0; i < NUM_BUCKETS; ++i)
260  if (buckets[i] != nullptr)
261  result->buckets[i] = buckets[i]->scalar_multiple(a);
262  return result;
263 }
264 
266  const Abstract_Polynomial & g
267 ) {
270  (*f) += g;
271  unsigned i = lglen(f->length());
272  unsigned m = i;
273  bool placed = false;
274  while (not placed and i < NUM_BUCKETS) {
275  if (buckets[i] != nullptr and not buckets[i]->is_zero()) {
276  (*f) += *(buckets[i]);
277  m = lglen(f->length());
278  }
279  if (m < (BUCKET_BASE << BUCKET_SHIFT * i)) {
280  placed = true;
281  if (not f->is_zero()) {
282  if (buckets[i] != nullptr)
283  delete buckets[i];
284  buckets[i] = f;
285  }
286  }
287  }
289  return *this;
290 }
291 
295  (*f) += g;
296  unsigned i = lglen(f->length());
297  bool placed = false;
298  unsigned m;
299  while (not placed and i < NUM_BUCKETS) {
300  if (buckets[i] != nullptr and not buckets[i]->is_zero()) {
301  (*f) -= *(buckets[i]);
302  m = lglen(f->length());
303  }
304  if (m < (BUCKET_BASE << BUCKET_SHIFT * i)) {
305  placed = true;
306  if (not f->is_zero()) {
307  if (buckets[i] != nullptr)
308  delete buckets[i];
309  buckets[i] = f;
310  }
311  }
312  }
314  return *this;
315 }
316 
318  const Prime_Field_Element & b, const Monomial & u,
319  const Abstract_Polynomial & g, bool subtract
320  )
321 {
322  unsigned i = lglen(g.length() + 1);
323  if (i >= NUM_BUCKETS) throw(new runtime_error("too large for buckets"));
325  f->add_polynomial_multiple(b, u, g, subtract);
327  if (buckets[i] == nullptr)
328  buckets[i] = f;
329  else if (buckets[i]->is_zero()) {
330  delete buckets[i];
331  buckets[i] = f;
332  } else {
333  (*f) += *(buckets[i]);
334  delete buckets[i];
335  buckets[i] = nullptr;
336  while (i < NUM_BUCKETS and lglen(f->length()) > i)
337  {
338  ++i;
339  if (buckets[i] != nullptr) {
340  (*f) += *(buckets[i]);
341  delete buckets[i];
343  }
344  }
345  if (i < NUM_BUCKETS) {
346  if (buckets[i] != nullptr)
347  delete buckets[i];
348  buckets[i] = f;
349  }
350  else
351  throw(new runtime_error("too large for buckets"));
352  }
354 }
355 
357  Polynomial_Linked_List * result = buckets[0];
360  return result;
361 }
362 
364  const Prime_Field_Element & a, const Monomial & t
365 ) {
366  unsigned i = 1;
367  while (i < NUM_BUCKETS and buckets[i] != nullptr
368  and buckets[i]->length() + 1 == BUCKET_BASE << BUCKET_SHIFT * i)
369  ++i;
370  if (i >= NUM_BUCKETS)
371  throw(new runtime_error("Buckets are full"));
372  if (buckets[i] == nullptr)
373  buckets[i] = new Polynomial_Linked_List(R);
374  buckets[i]->add_last(a, t);
376 }
377 
380  if (is_zero())
381  f = new Polynomial_Linked_List(R);
382  else
383  f = new Polynomial_Linked_List(*(buckets[0]));
384  for (unsigned i = 1; i < NUM_BUCKETS; ++i)
385  if (buckets[i] != nullptr and (not buckets[i]->is_zero())) {
386  *f += *(buckets[i]);
387  //delete buckets[i]; // removed to avoid deallocation errors
388  }
389  Abstract_Polynomial * result;
390  if (not constant_result)
391  result = f;
392  else {
393  result = new Constant_Polynomial(*f);
394  delete f;
395  }
396  return result;
397 }
398 
399 void Polynomial_Geobucket::print(unsigned i, ostream & os) const {
400  os << *(buckets[i]) << endl;
401 }
402 
403 void Polynomial_Geobucket::print(ostream & os) const {
404  for (unsigned i = 0; i < NUM_BUCKETS; ++i)
405  if (buckets[i] != nullptr and (not buckets[i]->is_zero())) {
406  if (i > 0)
407  os << " + ";
408  os << '(' << *(buckets[i]) << ')';
409  }
410  os << endl;
411 }
412 
417 ostream & operator << (ostream & os, const Polynomial_Geobucket & p) {
418  for (unsigned i = 0; i < NUM_BUCKETS; ++i)
419  if (p.buckets[i] != nullptr and (not p.buckets[i]->is_zero())) {
420  if (i > 0)
421  os << " + ";
422  os << '(' << *(p.buckets[i]) << ')';
423  }
424  return os;
425 }
426 
427 #endif
virtual unsigned length() const override
Returns the number of polynomials in the list.
The general class of a polynomial.
Definition: polynomial.hpp:101
~Polynomial_Geobucket()
Deallocates buckets, if they exist.
virtual Prime_Field_Element leading_coefficient() const override
returns the leading coefficient
Implementation of geobuckets.
virtual bool canMoveLeft() const override
const Monomial_Ordering * monomial_ordering() const
reports leading monomial’s monomial ordering
Definition: polynomial.hpp:130
Polynomial_Geobucket(Polynomial_Ring &R, Monomial_Ordering *order=generic_grevlex_ptr)
Initializes a polynomial with the given number of variables, over the given field.
void print(unsigned i, ostream &os=cout) const
prints the th bucket
friend ostream & operator<<(ostream &, const Polynomial_Geobucket &)
prints the geobucket in an explicitly geobucket form
virtual Polynomial_Geobucket & operator+=(const Abstract_Polynomial &g) override
Adds to this. Recomputes leading monomial.
virtual unsigned length() const override
how long is this polynomial?
A Constant_Polynomial is a polynomial that should not change.
virtual Geobucket_Iterator * new_mutable_iterator() override
An iterator that may modify the current position.
LLPolynomial_Iterator * pi
an iterator for the current bucket
virtual void set_currCoeff(const Prime_Field_Element &a) override
change coefficient in current position
virtual void add_last(const Prime_Field_Element &a, const Monomial &t) override
Adds as a monomial of this. (Not necessarily the last!)
virtual void moveLeft() override
Moves the iterator left: to the next larger monomial.
void recompute_leading_monomial()
You will need to call this after every operation that might modify the leading term.
unsigned lglen(unsigned i)
Log-length of , used to select a bucket for a polynomial of length .
virtual Polynomial_Geobucket * monomial_multiple(const Monomial &t) const override
Returns .
Iterator over linked list polynomials.
virtual const Prime_Field_Element & currCoeff() const override
Returns the coefficient of the monomial the iterator currently points to.
virtual Monomial & leading_monomial() const override
returns the leading monomial
virtual bool fellOff() const override
virtual Monomial & leading_monomial() const =0
leading monomial – call after sort_by_order()!
virtual Polynomial_Linked_List * zero_polynomial() const override
creates and returns a geobucket initialized to zero
const Abstract_Polynomial * p
the polynomial this points to
Definition: polynomial.hpp:272
virtual bool canMoveLeft() const override
Can this iterator move left, or would it fall off?
virtual void moveRight() override
Returns the monomial the iterator currently points to.
virtual const Monomial & currMonomial() const override
Reports the monomial at the current position.
Polynomial_Linked_List ** buckets
Array of ptrs to linked list polys; most initialized to nullptr.
virtual bool fellOff() const override
true iff the iterator no longer points to a valid monomial.
virtual Polynomial_Linked_List * detach_head() override
Detaches the head and recomputes leading monomial.
virtual Polynomial_Linked_List * scalar_multiple(const Prime_Field_Element &c) const override
Returns a new polynomial whose value is .
virtual void restart_iteration() override
This should move the iterator to the leading term.
virtual bool canMoveRight() const override
Can this iterator move right, or would it fall off?
virtual Polynomial_Geobucket & operator-=(const Abstract_Polynomial &g) override
Subtracts from this. Recomputes leading monomial.
virtual bool is_zero() const override
true iff the first node in the list is nullptr or has zero coeff
virtual void add_polynomial_multiple(const Prime_Field_Element &b, const Monomial &u, const Abstract_Polynomial &g, bool subtract=false) override
Adds to this. Recomputes leading monomial.
unsigned bucket_number
the bucket number at which we’re stopped
virtual Polynomial_Linked_List * detach_head() override
Detach and return leading term.
virtual void sort_by_order() override
sorts each geobucket
Abstract_Polynomial * canonicalize(bool constant_result=false)
returns a copy of this in a simplified linear form
Polynomials that need arithmetic typically descend from this class.
Definition: polynomial.hpp:305
virtual void set_monomial_ordering(const Monomial_Ordering *order, bool sort_anew=true) override
sets the monomial ordering for each bucket
virtual void moveRight() override
Moves right in the polynomial, to the next smaller monomial.
Implementation of monomials.
Definition: monomial.hpp:69
Element of a field of prime characteristic.
Definition: fields.hpp:137
interface to a monomial ordering
unsigned number_of_variables() const
number of variables – all monomials should agree with this (though it is never tested by the class) ...
Definition: polynomial.cpp:29
Encapsulates information about a polynomial ring for easy access: ground field, number of indetermina...
virtual Monomial & leading_monomial() const override
Returns the leading monomial — call sort_by_order() first!
virtual void set_currMonomial(const Monomial &t) override
change monomial in current position
virtual Polynomial_Geobucket * scalar_multiple(const Prime_Field_Element &a) const override
Returns .
virtual const Monomial & currMonomial() const override
Reports the monomial at the current position.
virtual void add_last(const Prime_Field_Element &c, const Monomial &t) override
Add this monomial as the last leading term.
virtual Prime_Field_Element leading_coefficient() const override
Returns the leading coefficient — call sort_by_order first!
virtual bool can_reduce(Abstract_Polynomial &other) const override
Whether this can reduce other. A geobucket should not generally be used to reduce other polynomials...
virtual bool is_zero() const override
is this polynomial zero?
Polynomials represented as a doubly linked list.
Used to iterate through a polynomial.
Definition: polynomial.hpp:224
virtual void add_polynomial_multiple(const Prime_Field_Element &a, const Monomial &t, const Abstract_Polynomial &q, bool subtract) override
"Fast" addition of to this.
virtual void set_currMonomial(const Monomial &t) override
change monomial in current position
virtual bool canMoveRight() const override
Can this iterator move right, or would it fall off?
virtual Polynomial_Linked_List * monomial_multiple(const Monomial &u) const override
Returns a new polynomial whose value is .
Polynomial_Geobucket * g
to save myself the hassle of static_cast<const Polynomial_Geobucket *>(p) every time I turn around ...
virtual Geobucket_Iterator * new_iterator() const override
An iterator that poses no risk of modifying the polynomial.
virtual const Prime_Field_Element & currCoeff() const override
Reports the coefficient at the current position.
Polynomial_Ring & R
data about polynomial ring
Definition: polynomial.hpp:207
virtual unsigned length() const =0
number of monomials
Polynomial_Ring & base_ring() const
ring in which this polynomial resides
Definition: polynomial.cpp:25
virtual void set_currCoeff(const Prime_Field_Element &a) override
change coefficient in current position
Iterates through polynomials using a geobucket representation. See Mutable_Polynomial_Iterator for de...
virtual void moveLeft() override
Moves left in the polynomial, to the next larger monomial.