Gröbner basis project
Codebase for research into Gröbner basis computation
polynomial_double_buffered.cpp
1 #ifndef __POLYNOMIAL_DOUBLE_BUFFERED_CPP_
2 #define __POLYNOMIAL_DOUBLE_BUFFERED_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_double_buffered.hpp"
22 
23 DB_Polynomial_Iterator::~DB_Polynomial_Iterator() { /* no action needed */ }
24 
26 
28 
30 
32  return current_position < head or current_position >= tail;
33 }
34 
36  return current_position - 1 < head;
37 }
38 
40  return current_position + 1 < tail;
41 }
42 
44  return T[current_position];
45 }
46 
48  return A[current_position];
49 }
50 
52  A[current_position] = a;
53 }
54 
56  T[current_position] = t;
57 }
58 
59 DB_Polynomial_Iterator::DB_Polynomial_Iterator(
60  const Double_Buffered_Polynomial * f, bool at_end
61 ) {
62  p = f;
63  A = f->coeffs[f->active_buffer];
64  T = f->mons[f->active_buffer];
65  if (at_end) current_position = f->tail;
66  else current_position = 0;
67  head = f->head;
68  tail = f->tail;
69 }
70 
71 Double_Buffered_Polynomial::Double_Buffered_Polynomial(Polynomial_Ring & R,
72  Monomial_Ordering * order
73 ) : Mutable_Polynomial(R, order) {
74  mons[0] = mons[1] = nullptr;
75  coeffs[0] = coeffs[1] = nullptr;
76  sizes[0] = sizes[1] = 0;
77  active_buffer = 0;
78  head = 0;
79  tail = 0;
80 }
81 
82 Double_Buffered_Polynomial::Double_Buffered_Polynomial(
83  Abstract_Polynomial const & p
85  mons[0] = mons[1] = nullptr;
86  coeffs[0] = coeffs[1] = nullptr;
87  sizes[0] = sizes[1] = 0;
88  active_buffer = 0;
89  head = 0;
90  tail = p.length();
91  expand_buffer(0, tail);
93  unsigned i = 0;
94  while (not pi->fellOff()) {
95  mons[0][i] = pi->currMonomial();
96  coeffs[0][i] = pi->currCoeff();
97  pi->moveRight();
98  ++i;
99  }
100  delete pi;
101 }
102 
103 Double_Buffered_Polynomial::~Double_Buffered_Polynomial() {
104  if (mons[0] != nullptr) {
105  for (unsigned i = 0; i < sizes[0]; ++i)
106  mons[0][i].deinitialize();
107  free(mons[0]);
108  free(coeffs[0]);
109  }
110  if (mons[1] != nullptr) {
111  for (unsigned i = 0; i < sizes[1]; ++i)
112  mons[1][i].deinitialize();
113  free(mons[1]);
114  free(coeffs[1]);
115  }
116 }
117 
119  return mons[active_buffer][head];
120 }
121 
123 const {
124  return coeffs[active_buffer][head];
125 }
126 
128  return tail - head;
129 }
130 
131 bool Double_Buffered_Polynomial::is_zero() const { return head == tail; }
132 
134 const {
135  return mons[active_buffer][head] | other.leading_monomial();
136 }
137 
139 ) const {
141  = new Double_Buffered_Polynomial(base_ring());
142  return result;
143 }
144 
146  const Monomial_Ordering * order, bool sort_anew
147 ) {
148  for (unsigned i = head; i < tail; ++i)
149  mons[active_buffer][i].set_monomial_ordering(order);
150  if (sort_anew)
151  sort_by_order();
152 }
153 
155  const Monomial & t
156 ) const {
158  unsigned i = p->active_buffer;
159  Monomial * M = p->mons[i];
160  for (unsigned j = head; j < tail; ++j)
161  M[j] *= t;
162  return p;
163 }
164 
166  const Prime_Field_Element & c)
167 const {
169  unsigned i = p->active_buffer;
170  Prime_Field_Element * C = p->coeffs[i];
171  for (unsigned j = head; j < tail; ++j)
172  C[j] *= c;
173  return p;
174 }
175 
177  const Abstract_Polynomial & p)
178 {
180  unsigned i = active_buffer;
181  unsigned j = 1 - active_buffer;
182  // make sure buffer can contain sum -- this is an overestimate
183  unsigned m = length() + p.length();
184  if (not test_buffer(j, m))
185  expand_buffer(j, m);
186  // insertion will start from point 0 in new buffer
187  unsigned k = 0;
188  unsigned l = head;
189  while (not pi->fellOff() and l < tail) {
190  if (mons[i][l].is_like(pi->currMonomial())) {
191  mons[j][k] = mons[i][l];
192  coeffs[j][k] = coeffs[i][l] + pi->currCoeff();
193  ++l;
194  pi->moveRight();
195  } else if (pi->currMonomial() > mons[i][l]) {
196  mons[j][k] = pi->currMonomial();
197  coeffs[j][k] = pi->currCoeff();
198  pi->moveRight();
199  } else {
200  mons[j][k] = mons[i][l];
201  coeffs[j][k] = coeffs[i][l];
202  ++l;
203  }
204  if (not coeffs[j][k].is_zero())
205  ++k;
206  }
207  while (not pi->fellOff()) {
208  mons[j][k] = pi->currMonomial();
209  coeffs[j][k] = pi->currCoeff();
210  ++k;
211  pi->moveRight();
212  }
213  while (l < tail) {
214  mons[j][k] = mons[i][l];
215  coeffs[j][k] = coeffs[i][l];
216  ++k;
217  ++l;
218  }
219  delete pi;
220  // adjust to new buffer
221  active_buffer = j;
222  head = 0;
223  tail = k;
224  return *this;
225 }
226 
228  const Abstract_Polynomial & p
229 ) {
231  unsigned i = active_buffer;
232  unsigned j = 1 - active_buffer;
233  // make sure buffer can contain sum -- this is an overestimate
234  unsigned m = length() + p.length();
235  if (not test_buffer(j, m))
236  expand_buffer(j, m);
237  // insertion will start from point 0 in new buffer
238  unsigned k = 0;
239  unsigned l = head;
240  while (not pi->fellOff() and l < tail) {
241  if (mons[i][l].is_like(pi->currMonomial())) {
242  mons[j][k] = mons[i][l];
243  coeffs[j][k] = coeffs[i][l] - pi->currCoeff();
244  ++l;
245  pi->moveRight();
246  } else if (pi->currMonomial() > mons[i][l]) {
247  mons[j][k] = pi->currMonomial();
248  coeffs[j][k] = -(pi->currCoeff());
249  pi->moveRight();
250  } else {
251  mons[j][k] = mons[i][l];
252  coeffs[j][k] = coeffs[i][l];
253  ++l;
254  }
255  if (not coeffs[j][k].is_zero())
256  ++k;
257  }
258  while (not pi->fellOff()) {
259  mons[j][k] = pi->currMonomial();
260  coeffs[j][k] = -(pi->currCoeff());
261  ++k;
262  pi->moveRight();
263  }
264  while (l < tail) {
265  mons[j][k] = mons[i][l];
266  coeffs[j][k] = coeffs[i][l];
267  ++k;
268  ++l;
269  }
270  delete pi;
271  // adjust to new buffer
272  active_buffer = j;
273  head = 0;
274  tail = k;
275  return *this;
276 }
277 
279  const Prime_Field_Element & a,
280  const Monomial & u,
281  const Abstract_Polynomial & p,
282  bool subtract
283  )
284 {
286  bool true_multiple = not u.is_one();
287  unsigned i = active_buffer;
288  unsigned j = 1 - active_buffer;
289  // make sure buffer can contain sum -- this is an overestimate
290  unsigned m = length() + p.length();
291  if (not test_buffer(j, m))
292  expand_buffer(j, m);
293  // insertion will start from point 0 in new buffer
294  unsigned k = 0;
295  unsigned l = head;
296  while (not pi->fellOff() and l < tail) {
297  if (mons[i][l].like_multiple(pi->currMonomial(), u)) {
298  mons[j][k] = mons[i][l];
299  coeffs[j][k] = pi->currCoeff();
300  coeffs[j][k] *= a;
301  if (subtract)
302  coeffs[j][k].negate();
303  coeffs[j][k] += coeffs[i][l];
304  ++l;
305  pi->moveRight();
306  } else if (mons[i][l].larger_than_multiple(pi->currMonomial(), u)) {
307  mons[j][k] = mons[i][l];
308  coeffs[j][k] = coeffs[i][l];
309  ++l;
310  } else {
311  mons[j][k] = pi->currMonomial();
312  if (true_multiple)
313  mons[j][k] *= u;
314  coeffs[j][k] = pi->currCoeff();
315  coeffs[j][k] *= a;
316  if (subtract)
317  coeffs[j][k].negate();
318  pi->moveRight();
319  }
320  if (not coeffs[j][k].is_zero())
321  ++k;
322  }
323  while (not pi->fellOff()) {
324  mons[j][k] = pi->currMonomial();
325  mons[j][k] *= u;
326  coeffs[j][k] = pi->currCoeff();
327  coeffs[j][k] *= a;
328  if (subtract)
329  coeffs[j][k].negate();
330  ++k;
331  pi->moveRight();
332  }
333  while (l < tail) {
334  mons[j][k] = mons[i][l];
335  coeffs[j][k] = coeffs[i][l];
336  ++k;
337  ++l;
338  }
339  delete pi;
340  // adjust to new buffer
341  active_buffer = j;
342  head = 0;
343  tail = k;
344 }
345 
347 {
348  Monomial * M = mons[active_buffer];
349  Prime_Field_Element * A = coeffs[active_buffer];
350  // if (weights == nullptr)
351  if (true) {
352  // insertion sort, as we don't expect worst case
353  for (int i = 0; i < tail; ++i) {
354  Monomial t(M[i]);
355  Prime_Field_Element c(A[i]);
356  int j = i;
357  for (/* */; j > 0 and M[i] > M[j-1]; --j) {
358  A[j] = A[j-1];
359  M[j] = M[j-1];
360  }
361  if (i != j) {
362  A[j] = c;
363  M[j] = t;
364  }
365  }
366  }
367 }
368 
370  DB_Polynomial_Iterator * result = new DB_Polynomial_Iterator(this);
371  return result;
372 }
373 
374 Polynomial_Iterator * Double_Buffered_Polynomial::begin() const {
375  return new DB_Polynomial_Iterator(this);
376 }
377 
378 Polynomial_Iterator * Double_Buffered_Polynomial::end() const {
379  return new DB_Polynomial_Iterator(this, true);
380 }
381 
384 {
385  DB_Polynomial_Iterator * result = new DB_Polynomial_Iterator(this);
386  return result;
387 }
388 
390  const Prime_Field_Element & a, const Monomial & t
391 ) {
392  unsigned i = active_buffer;
393  // can we store in current buffer?
394  if (tail + 1 >= sizes[i]) {
395  // no: store in other buffer
396  unsigned j = 1 - i;
397  if (not test_buffer(j, length() + 1))
398  expand_buffer(j, length() + 1);
399  // copy data from current buffer to other buffer
400  Monomial * T = mons[j];
401  Monomial * U = mons[i];
402  Prime_Field_Element * A = coeffs[j];
403  Prime_Field_Element * B = coeffs[i];
404  unsigned k = head = 0;
405  for (unsigned l = head; l < tail; ++l, ++k) {
406  T[k] = U[l];
407  A[k] = B[l];
408  }
409  tail = k;
410  active_buffer = i = j;
411  }
412  // add new term
413  coeffs[i][tail] = a;
414  mons[i][tail] = t;
415  ++tail;
416 }
417 
420  base_ring(), coeffs[active_buffer][head], mons[active_buffer][head]);
421  ++head;
422  return result;
423 }
424 
425 #endif
The general class of a polynomial.
Definition: polynomial.hpp:101
virtual bool can_reduce(Abstract_Polynomial &other) const override
can this reduce other?
virtual Double_Buffered_Polynomial * zero_polynomial() const override
zero polynomial of this type
virtual Double_Buffered_Polynomial * scalar_multiple(const Prime_Field_Element &c) const override
multiple of this and c
const Monomial_Ordering * monomial_ordering() const
reports leading monomial’s monomial ordering
Definition: polynomial.hpp:130
long long current_position
current position in the list
virtual bool canMoveRight() const override
Can this iterator move right, or would it fall off?
virtual bool canMoveLeft() const override
virtual Polynomial_Iterator * new_iterator() const =0
An iterator that poses no risk of modifying the polynomial.
virtual DB_Polynomial_Iterator * new_iterator() const override
An iterator that poses no risk of modifying the polynomial.
virtual void moveRight()=0
Moves right in the polynomial, to the next smaller monomial.
virtual const Prime_Field_Element & currCoeff() const =0
Reports the coefficient at the current position.
virtual void restart_iteration() override
This should move the iterator to the leading term.
virtual Monomial & leading_monomial() const =0
leading monomial – call after sort_by_order()!
virtual Prime_Field_Element leading_coefficient() const override
leading coefficient – call after sort_by_order()!
const Abstract_Polynomial * p
the polynomial this points to
Definition: polynomial.hpp:272
void negate()
“Negates” this.
Definition: fields.cpp:90
virtual Double_Buffered_Polynomial * monomial_multiple(const Monomial &t) const override
multiple of this and u
virtual Polynomial_Linked_List * detach_head() override
Remove and return the head.
Iterator over double-buffered polynomials.
bool is_one() const
all exponents 0?
Definition: monomial.cpp:176
unsigned tail
position of last monomial
virtual void set_currMonomial(const Monomial &t) override
change monomial in current position
virtual unsigned length() const override
number of monomials
virtual void sort_by_order() override
sort according to the leading monomial’s ordering
virtual DB_Polynomial_Iterator * new_mutable_iterator() override
An iterator that may modify the current position.
virtual bool is_zero() const override
is this polynomial zero?
virtual void set_currCoeff(const Prime_Field_Element &a) override
change coefficient in current position
virtual bool fellOff() const =0
Polynomials that need arithmetic typically descend from this class.
Definition: polynomial.hpp:305
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
Encapsulates information about a polynomial ring for easy access: ground field, number of indetermina...
virtual void moveLeft() override
Moves left in the polynomial, to the next larger monomial.
virtual void add_last(const Prime_Field_Element &a, const Monomial &t) override
Attach a new monomial to the tail – check that it belongs at tail!
virtual bool fellOff() const override
virtual Monomial & leading_monomial() const override
leading monomial – call after sort_by_order()!
virtual const Prime_Field_Element & currCoeff() const override
Reports the coefficient at the current position.
Monomial * T
pointer to monomials
Polynomials represented as a doubly linked list.
virtual void add_polynomial_multiple(const Prime_Field_Element &a, const Monomial &u, const Abstract_Polynomial &p, bool subtract) override
add monomial multiple of other
Used to iterate through a polynomial.
Definition: polynomial.hpp:224
virtual const Monomial & currMonomial() const =0
Reports the monomial at the current position.
Prime_Field_Element * A
pointer to coefficients
virtual const Monomial & currMonomial() const override
Reports the monomial at the current position.
virtual Mutable_Polynomial & operator-=(const Abstract_Polynomial &p) override
subtract another polynomial
Polynomials implemented using double buffers.A double-buffered polynomial maintains at all times two ...
virtual void set_monomial_ordering(const Monomial_Ordering *order, bool sort_anew=true) override
set the monomial ordering and sort the polynomials (optionally, but by default)
virtual unsigned length() const =0
number of monomials
Polynomial_Ring & base_ring() const
ring in which this polynomial resides
Definition: polynomial.cpp:25
virtual Mutable_Polynomial & operator+=(const Abstract_Polynomial &p) override
add another polynomial
unsigned head
position of first monomial