Gröbner basis project
Codebase for research into Gröbner basis computation
polynomial_linked_list.cpp
1 #ifndef __POLYNOMIAL_LINKED_LIST_
2 #define __POLYNOMIAL_LINKED_LIST_
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_linked_list.hpp"
22 
30 
31 void * Monomial_Node::operator new(size_t size) {
32  if (monododa == nullptr) monododa = new Grading_Order_Data_Allocator<Monomial_Node>(size);
33  Monomial_Node * result = monododa->get_new_block();
34  return result;
35 }
36 
37 void Monomial_Node::operator delete(void *t) {
38  monododa->return_used_block(static_cast<Monomial_Node *>(t));
39 }
40 
42  : t(u), c(a)
43 { }
44 
46 : t(u), c(F.unity())
47 {}
48 
50 
52 
54  return iter_curr != nullptr and iter_curr->next != nullptr;
55 }
56 
58  return iter_curr != nullptr and iter_curr->prev != nullptr;
59 }
60 
61 bool LLPolynomial_Iterator::fellOff() const { return iter_curr == nullptr; }
62 
64  return iter_curr->t;
65 }
66 
68  return iter_curr->c;
69 }
70 
72  if (!fellOff()) iter_curr->c = a;
73 }
74 
76  if (!fellOff()) iter_curr->t = t;
77 }
78 
79 
81  Polynomial_Linked_List * poly, bool at_end
82 ) {
83  p = poly;
84  iter_curr = p->head;
85  if (at_end and iter_curr != nullptr)
86  while (iter_curr->next != nullptr)
87  iter_curr = iter_curr->next;
88 }
89 
91  const Polynomial_Linked_List * poly, bool at_end)
92 {
93  p = const_cast<Polynomial_Linked_List *>(poly);
94  iter_curr = p->head;
95  if (at_end and iter_curr != nullptr)
96  while (iter_curr->next != nullptr)
97  iter_curr = iter_curr->next;
98 }
99 
101  iter_curr = p->head;
102 }
103 
105  Polynomial_Ring & R,
106  const Monomial_Ordering * order
107 ) : Mutable_Polynomial(R, order)
108 {
109  head = nullptr;
110 }
111 
113  Polynomial_Ring & R,
114  const Monomial & t,
115  const Monomial_Ordering * order
116 ) : Mutable_Polynomial(R, order)
117 {
118  if (order == nullptr) {
119  if (t.monomial_ordering() == nullptr)
120  order = generic_grevlex_ptr;
121  else
122  order = t.monomial_ordering();
123  }
124  head = new Monomial_Node(R.ground_field(), t);
125  if (order != t.monomial_ordering())
126  head->t.set_monomial_ordering(order);
127  head->next = nullptr;
128 }
129 
131  Polynomial_Ring & R,
132  const Prime_Field_Element & c, const Monomial & t,
133  const Monomial_Ordering * order
134 ) : Mutable_Polynomial(R, order), head(new Monomial_Node(c, t))
135 {
136  if (order == nullptr) {
137  if (t.monomial_ordering() == nullptr)
138  order = generic_grevlex_ptr;
139  else
140  order = t.monomial_ordering();
141  }
142  if (order != t.monomial_ordering())
143  head->t.set_monomial_ordering(order);
144  head->next = nullptr;
145 }
146 
148  Polynomial_Ring & R,
149  Monomial_Node * node,
150  const Monomial_Ordering * order
151 ) : Mutable_Polynomial(R, order)
152 {
153  if (order == nullptr) {
154  if (node == nullptr or node->t.monomial_ordering() == nullptr)
155  order = generic_grevlex_ptr;
156  else
157  order = node->t.monomial_ordering();
158  }
159  head = node;
160  if (node != nullptr) {
161  node->next = node->prev = nullptr; // to be safe
162  head->t.set_monomial_ordering(order);
163  }
164 }
165 
167  const Polynomial_Linked_List & other
168 ) : Mutable_Polynomial(other.base_ring(), other.monomial_ordering())
169 {
170  head = nullptr;
171  Monomial_Node *curr = nullptr;
172  Monomial_Node *other_curr = other.head;
173  while (other_curr != nullptr) {
174  Monomial_Node * next = new Monomial_Node(*other_curr);
175  if (head == nullptr) head = curr = next;
176  else
177  {
178  curr->next = next;
179  curr->next->prev = curr;
180  curr = next;
181  }
182  other_curr = other_curr->next;
183  }
184  curr->next = nullptr;
185 }
186 
189 {
191  Monomial_Node *curr = nullptr;
192  while (!pi->fellOff()) {
193  if (curr == nullptr) {
194  head = curr = new Monomial_Node(pi->currCoeff(), pi->currMonomial());
195  curr->prev = nullptr;
196  }
197  else {
198  curr->next = new Monomial_Node(pi->currCoeff(), pi->currMonomial());
199  curr->next->prev = curr;
200  curr = curr->next;
201  }
202  pi->moveRight();
203  }
204  delete pi;
205  curr->next = nullptr;
206 }
207 
209  while (head != nullptr) {
210  Monomial_Node * tmp = head->next;
211  delete head;
212  head = tmp;
213  }
214 }
215 
217  return head == nullptr or head->c.is_zero();
218 }
219 
221 
223  return head->c;
224 }
225 
227  unsigned i = 0;
228  for (Monomial_Node *curr = head; curr != nullptr; ++i) { curr = curr->next; }
229  return i;
230 }
231 
233  const Monomial_Ordering * ord, bool sort_anew
234 ) {
235  for (Monomial_Node *curr = head; curr != nullptr; curr = curr->next)
236  curr->t.set_monomial_ordering(ord);
237  if (sort_anew)
238  sort_by_order();
239 }
240 
242  return new Polynomial_Linked_List(R);
243 }
244 
246  const Monomial &u
247 ) const {
249  for (Monomial_Node *curr = p->head; curr != nullptr and !(curr->c.is_zero());
250  curr = curr->next)
251  curr->t *= u;
252  return p;
253 }
254 
256  const Prime_Field_Element &c
257 ) const {
259  for (Monomial_Node *curr = p->head; curr != nullptr and !(curr->c.is_zero());
260  curr = curr->next)
261  curr->c *= c;
262  return p;
263 }
264 
266  const Abstract_Polynomial &other
267 ) {
268  // need an iterator
269  Polynomial_Iterator * oi = other.new_iterator();
270  // add until one of the polynomials is exhausted
271  for (Monomial_Node *p = head;
272  (!oi->fellOff() and !(oi->currCoeff().is_zero()))
273  and (p != nullptr and !(p->c.is_zero()));
274  )
275  {
276  DEG_TYPE a = p->t.ordering_degree();
277  while (not oi->fellOff() and a < oi->currMonomial().ordering_degree()){
278  Monomial_Node *r = new Monomial_Node(oi->currCoeff(), oi->currMonomial());
279  r->prev = p->prev;
280  if (p->prev != nullptr) p->prev->next = r;
281  if (head == p) head = r;
282  p->prev = r;
283  r->next = p;
284  oi->moveRight();
285  }
286  if (not oi->fellOff()) {
287  if (p->t.is_like(oi->currMonomial())) {
288  p->c += oi->currCoeff();
289  oi->moveRight();
290  if (not p->c.is_zero())
291  p = p->next;
292  else {
293  Monomial_Node *r = p->next;
294  if (p->prev != nullptr) p->prev->next = r;
295  if (r != nullptr) r->prev = p->prev;
296  if (head == p) head = r;
297  delete p;
298  p = r;
299  }
300  } else if (p->t > oi->currMonomial())
301  p = p->next;
302  else {
303  Monomial_Node *r = new Monomial_Node(oi->currCoeff(), oi->currMonomial());
304  r->prev = p->prev;
305  if (p->prev != nullptr) p->prev->next = r;
306  if (head == p) head = r;
307  p->prev = r;
308  r->next = p;
309  oi->moveRight();
310  }
311  }
312  }
313  // if this polynomial is exhausted, we need to add what remains of other
314  if (!oi->fellOff() and !(oi->currCoeff().is_zero())) {
315  if (head == nullptr) {
316  head = new Monomial_Node(oi->currCoeff(), oi->currMonomial());
317  head->next = head->prev = nullptr;
318  oi->moveRight();
319  }
320  Monomial_Node *p = head;
321  while (p->next != nullptr) p = p->next;
322  while (!oi->fellOff() and !(oi->currCoeff().is_zero())) {
323  p->next = new Monomial_Node(oi->currCoeff(), oi->currMonomial());
324  p->next->prev = p;
325  p = p->next;
326  oi->moveRight();
327  }
328  p->next = nullptr;
329  }
330  delete oi;
331  return *this;
332 }
333 
335  const Abstract_Polynomial &other
336 ) {
337  // need an iterator
338  Polynomial_Iterator * oi = other.new_iterator();
339  // add until one of the polynomials is exhausted
340  for (Monomial_Node *p = head;
341  (!oi->fellOff() and !(oi->currCoeff().is_zero()))
342  and (p != nullptr and !(p->c.is_zero()));
343  )
344  {
345  if (p->t.is_like(oi->currMonomial())) {
346  p->c += oi->currCoeff();
347  if (p->c.is_zero()) {
348  Monomial_Node *r = p->next;
349  if (p->prev != nullptr) p->prev->next = r;
350  if (r != nullptr) r->prev = p->prev;
351  if (head == p) head = r;
352  delete p;
353  p = r;
354  oi->moveRight();
355  }
356  } else if (p->t > oi->currMonomial())
357  p = p->next;
358  else {
359  Monomial_Node *r = new Monomial_Node(oi->currCoeff(), oi->currMonomial());
360  r->prev = p->prev;
361  if (p->prev != nullptr) p->prev->next = r;
362  if (head == p) head = r;
363  p->prev = r;
364  r->next = p;
365  oi->moveRight();
366  }
367  }
368  // if this polynomial is exhausted, we need to add what remains of other
369  if (!oi->fellOff() and !(oi->currCoeff().is_zero())) {
370  if (head == nullptr) {
371  head = new Monomial_Node(-(oi->currCoeff()), oi->currMonomial());
372  head->next = head->prev = nullptr;
373  oi->moveRight();
374  }
375  Monomial_Node *p = head;
376  while (p->next != nullptr) p = p->next;
377  while (!oi->fellOff() and !(oi->currCoeff().is_zero())) {
378  p->next = new Monomial_Node(oi->currCoeff(), oi->currMonomial());
379  p->next->prev = p;
380  p = p->next;
381  oi->moveRight();
382  }
383  p->next = nullptr;
384  }
385  delete oi;
386  return *this;
387 }
388 
390  const Prime_Field_Element &a,
391  const Monomial &t,
392  const Abstract_Polynomial &q,
393  bool subtract
394 ) {
395  // cout << "\tadding " << a << " * " << t << " * (" << q << ')' << endl;
396  // need an iterator
398  // first add monomials until this or q is exhausted
399  for (Monomial_Node *curr = head;
400  curr != nullptr and !(curr->c.is_zero()) and
401  !oi->fellOff() and !(oi->currCoeff().is_zero());
402  )
403  {
404  if (curr->t.like_multiple(oi->currMonomial(), t)) {
405  if (subtract) curr->c -= a * oi->currCoeff();
406  else curr->c += a * oi->currCoeff();
407  if ((curr->c).is_zero()) {
408  if (curr->prev != nullptr) curr->prev->next = curr->next;
409  if (curr->next != nullptr) curr->next->prev = curr->prev;
410  Monomial_Node *tmp = curr->next;
411  if (head == curr) head = tmp;
412  delete curr;
413  curr = tmp;
414  }
415  else
416  curr = curr->next;
417  oi->moveRight();
418  } else if (curr->t.larger_than_multiple(oi->currMonomial(), t)) {
419  curr = curr->next;
420  } else { // smaller
422  if (subtract) c = -c;
423  Monomial_Node *new_node = new Monomial_Node(c, oi->currMonomial());
424  new_node->t *= t;
425  new_node->c *= a;
426  if (new_node->c.is_zero())
427  delete new_node;
428  else {
429  new_node->prev = curr->prev;
430  if (curr->prev != nullptr) curr->prev->next = new_node;
431  if (head == curr) head = new_node;
432  curr->prev = new_node;
433  new_node->next = curr;
434  oi->moveRight();
435  }
436  }
437  }
438  // if this is exhausted but q is not, add the remaining monomials
439  if (!oi->fellOff() and !(oi->currCoeff().is_zero())) {
440  if (head == nullptr) {
441  head = new Monomial_Node(-(oi->currCoeff()), oi->currMonomial());
442  head->t *= t;
443  head->c *= a;
444  head->next = head->prev = nullptr;
445  oi->moveRight();
446  }
447  Monomial_Node * curr = head;
448  while (curr->next != nullptr) curr = curr->next;
449  while (!oi->fellOff() and !(oi->currCoeff().is_zero())) {
450  if (subtract)
451  curr->next = new Monomial_Node(-(oi->currCoeff()), oi->currMonomial());
452  else
453  curr->next = new Monomial_Node(oi->currCoeff(), oi->currMonomial());
454  curr->next->prev = curr;
455  curr = curr->next;
456  curr->t *= t;
457  curr->c *= a;
458  oi->moveRight();
459  }
460  curr->next = nullptr;
461  }
462  delete oi;
463  // cout << "\tresulted in " << *this << endl;
464 }
465 
467 {
468  // insertion sort, as we don't expect worst case
469  for (Monomial_Node *curr = head->next; curr != nullptr; /* */) {
470  while (curr->t > curr->prev->t) {
471  Monomial_Node *tmp = curr->next;
472  curr->prev->next = tmp;
473  if (tmp != nullptr) tmp->prev = curr->prev;
474  curr->next = curr->prev;
475  curr->prev = curr->prev->prev;
476  curr->prev->prev = curr;
477  curr = tmp;
478  }
479  }
480 }
481 
483  return new LLPolynomial_Iterator(this);
484 }
485 
487  return new LLPolynomial_Iterator(this);
488 }
489 
491  return new LLPolynomial_Iterator(this, true);
492 }
493 
495  return new LLPolynomial_Iterator(this);
496 }
497 
499  Monomial_Node *tmp = head;
500  if (head != nullptr) {
501  head = head->next;
502  if (head != nullptr) head->prev = nullptr;
503  }
504  Polynomial_Linked_List * result = new Polynomial_Linked_List(R, tmp);
505  return result;
506 }
507 
509  const Prime_Field_Element & c,
510  const Monomial & t
511 ) {
512  if (head == nullptr) {
513  head = new Monomial_Node(c, t);
514  head->prev = head->next = nullptr;
515  } else {
516  Monomial_Node * tail = head;
517  while (tail != nullptr and tail->next != nullptr) { tail = tail->next; }
518  tail->next = new Monomial_Node(c, t);
519  tail->next->prev = tail;
520  tail->next->next = nullptr;
521  }
522 }
523 
524 #endif
virtual unsigned length() const override
Returns the number of polynomials in the list.
The general class of a polynomial.
Definition: polynomial.hpp:101
virtual LLPolynomial_Iterator * new_mutable_iterator() override
An iterator that may modify the current position.
virtual bool is_zero() const =0
is this polynomial zero?
special memory pool allocator for Grevlex_Order_Data and WGrevlex_Order_Data
Definition: goda.hpp:67
const Monomial_Ordering * monomial_ordering() const
reports leading monomial’s monomial ordering
Definition: polynomial.hpp:130
virtual Prime_Field & ground_field() const
ground field
virtual Polynomial_Iterator * new_iterator() const =0
An iterator that poses no risk of modifying the polynomial.
Monomial_Node(const Prime_Field_Element &a, const Monomial &u)
Monomial u with coefficient a. Both are copied, and can be deleted.
virtual void moveRight()=0
Moves right in the polynomial, to the next smaller monomial.
Prime_Field_Element & coefficient()
This term’s coefficient.
virtual void restart_iteration() override
Initializes at the leading monomial.
LLPolynomial_Iterator * pi
an iterator for the current bucket
Tool for Polynomial_Linked_List.
Monomial t
the monomial in this node
virtual ~Polynomial_Linked_List()
deletes all monomial nodes
bool is_zero() const
Is this the additive identity?
Definition: fields.hpp:180
virtual const Prime_Field_Element & currCoeff() const =0
Reports the coefficient at the current position.
virtual Polynomial_Linked_List & operator-=(const Abstract_Polynomial &other) override
Subtracts other from this, and returns the result.
Iterator over linked list polynomials.
virtual const Prime_Field_Element & currCoeff() const override
Returns the coefficient of the monomial the iterator currently points to.
DEG_TYPE ordering_degree() const
returns the ordering degree for this Monomial
Definition: monomial.hpp:177
Monomial_Node * next
for linking
TYPE * get_new_block()
allocates and returns a block of memory
Definition: goda.hpp:108
Information necessary for a field modulo a prime.
Definition: fields.hpp:49
virtual bool fellOff() const override
void set_monomial_ordering(const Monomial_Ordering *mord)
sets the Monomial_Ordering associated with this Monomial
Definition: monomial.cpp:211
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 const Monomial & currMonomial() const override
Reports the monomial at the current position.
virtual void set_monomial_ordering(const Monomial_Ordering *ord, bool sort_anew=true) override
set the monomial ordering and sort the polynomials (optionally, but by default)
virtual bool fellOff() const override
true iff the iterator no longer points to a valid monomial.
virtual Polynomial_Linked_List * scalar_multiple(const Prime_Field_Element &c) const override
Returns a new polynomial whose value is .
virtual bool canMoveRight() const override
Can this iterator move right, or would it fall off?
Monomial_Node * head
first monomial in the list, returned by leading_monomial()
virtual bool is_zero() const override
true iff the first node in the list is nullptr or has zero coeff
virtual Polynomial_Iterator * begin() const override
an iterator that poses no risk of modifying the polynomial
virtual Polynomial_Linked_List * detach_head() override
Detach and return leading term.
virtual bool fellOff() const =0
Polynomials that need arithmetic typically descend from this class.
Definition: polynomial.hpp:305
Monomial_Node * prev
for linking
Implementation of monomials.
Definition: monomial.hpp:69
Element of a field of prime characteristic.
Definition: fields.hpp:137
interface to a monomial ordering
friend class LLPolynomial_Iterator
to iterate over this and possibly change it
virtual Polynomial_Linked_List & operator+=(const Abstract_Polynomial &other) override
Adds other to this, and returns the result.
Polynomial_Linked_List(Polynomial_Ring &R, const Monomial_Ordering *order=generic_grevlex_ptr)
initialize to zero
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 Polynomial_Iterator * end() const override
an iterator that poses no risk of modifying the polynomial
virtual void add_last(const Prime_Field_Element &c, const Monomial &t) override
Add this monomial as the last leading term.
Monomial & monomial()
This term’s monomial, or power product. The coefficient is not included.
virtual Prime_Field_Element leading_coefficient() const override
Returns the leading coefficient — call sort_by_order first!
const Monomial_Ordering * monomial_ordering() const
the Monomial_Ordering associated with this Monomial
Definition: monomial.hpp:165
virtual Polynomial_Linked_List * zero_polynomial() const override
Returns as simple a zero polynomial as I can muster, short of this being nullptr. ...
Polynomials represented as a doubly linked list.
Used to iterate through a polynomial.
Definition: polynomial.hpp:224
void return_used_block(TYPE *freed_block)
returns a block of memory that is no longer needed to the pool
Definition: goda.hpp:121
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 const Monomial & currMonomial() const =0
Reports the monomial at the current position.
virtual Polynomial_Linked_List * monomial_multiple(const Monomial &u) const override
Returns a new polynomial whose value is .
virtual LLPolynomial_Iterator * new_iterator() const override
an iterator that poses no risk of modifying the polynomial
Grading_Order_Data_Allocator< Monomial_Node > * monododa
memory manager for Monomial_Node
Prime_Field_Element c
the monomial’s coefficient
Polynomial_Ring & R
data about polynomial ring
Definition: polynomial.hpp:207
Polynomial_Ring & base_ring() const
ring in which this polynomial resides
Definition: polynomial.cpp:25
LLPolynomial_Iterator(Polynomial_Linked_List *poly, bool at_end=false)
Initializes at the leading monomial.
virtual void set_currCoeff(const Prime_Field_Element &a) override
change coefficient in current position
virtual void sort_by_order() override
Sort by specified weight order.