Gröbner basis project
Codebase for research into Gröbner basis computation
hilbert_functions.cpp
1 #ifndef __HILBERT_FUNCTIONS_CPP_
2 #define __HILBERT_FUNCTIONS_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 <set>
22 #include <list>
23 #include <vector>
24 #include <cstring>
25 #include <iostream>
26 #include <algorithm>
27 
28 using std::set; using std::list; using std::vector;
29 
30 #include "system_constants.hpp"
31 
32 #include "fields.hpp"
33 #include "monomial.hpp"
34 #include "polynomial_linked_list.hpp"
35 
36 #include "hilbert_functions.hpp"
37 
38 extern list<Monomial> colon_ideal_without_ideals(
39  const list<Monomial> &,
40  const Monomial &
41 );
42 
43 bool is_zero_base_case(const list<Monomial> & T) {
44  bool result = true; // innocent until proven guilty
45  const Monomial & t = T.front();
46  NVAR_TYPE n = t.num_vars();
47  bool * d = new bool [n] {false};
48  for (const Monomial & t : T) {
49  bool found = false;
50  for (NVAR_TYPE k = 0; result and k < n; ++k) {
51  if (t.degree(k) != 0) {
52  if (found) { result = false; }
53  else {
54  found = true;
55  if (d[k]) { result = false; }
56  else { d[k] = true; }
57  }
58  }
59  }
60  }
61  delete [] d;
62  return result;
63 }
64 
65 Dense_Univariate_Integer_Polynomial * solve_one_monomial_case(
66  const list<Monomial> & T,
67  const WT_TYPE * grading
68 ) {
69  DEG_TYPE n = T.front().weighted_degree(grading) + 1;
70  DEG_TYPE d = n - 1;
73  result->set_coefficient(0, 1);
74  result->set_coefficient(d, -1);
75  return result;
76 }
77 
79  const list<Monomial> & T,
80  const WT_TYPE * grading
81 ) {
82  DEG_TYPE n = T.front().weighted_degree(grading) + 1;
83  DEG_TYPE d = n;
84  list<Monomial>::const_iterator ti = T.begin();
85  for (++ti; ti != T.end(); ++ti)
86  {
87  n += ti->weighted_degree(grading);
88  if (ti->weighted_degree(grading) + 1 > d)
89  d = ti->weighted_degree(grading) + 1;
90  }
93  result->set_coefficient(0, 1);
96  intermediate->set_coefficient(0, 1);
97  for (ti = T.begin(); ti != T.end(); ++ti) {
98  intermediate->set_coefficient(ti->weighted_degree(grading), -1);
99  result->multiply_by(*intermediate);
100  intermediate->set_coefficient(ti->weighted_degree(grading), 0);
101  }
102  delete intermediate;
103  return result;
104 }
105 
106 list<Monomial>::const_iterator is_one_base_case(const list<Monomial> & T) {
107  list<Monomial>::const_iterator result = T.end();
108  for (
109  list<Monomial>::const_iterator ti = T.begin();
110  (result != T.end()) and ti != T.end();
111  ++ti
112  ) {
113  list<Monomial> U;
114  for (const Monomial & u : T)
115  if (not u.is_like(*ti))
116  U.push_back(u);
117  if (is_zero_base_case(U))
118  result = ti;
119  }
120  return result;
121 }
122 
124  const list<Monomial> & T, list<Monomial>::const_iterator ui,
125  const WT_TYPE * grading
126 ) {
127  // copy T and remove the monomial that isn't a simple power
128  list<Monomial> U(T);
129  Monomial p = *ui;
130  U.erase(ui);
132  DEG_TYPE d = 0;
133  DEG_TYPE max_d = 0;
134  for (const Monomial & u : U)
135  {
136  bool found_index = false;
137  unsigned j = 0;
138  for (/* already initialized */ ; not found_index and j < u.num_vars(); ++j)
139  if (u.degree(j) != 0)
140  found_index = true;
141  --j; // to compensate for a forced increment at the end of the loop
142  DEG_TYPE e = (u.degree(j) > p.degree(j)) ?
143  u.degree(j) - p.degree(j) : 0;
144  d += (grading == nullptr) ? e : grading[j] * e;
145  if (max_d < e)
146  max_d = e;
147  }
151  = new Dense_Univariate_Integer_Polynomial(max_d + 1);
152  fac->set_coefficient(0, 1);
153  prod->set_coefficient(0, 1);
154  for (const Monomial & u : U)
155  {
156  NVAR_TYPE k = 0;
157  for (/* */; k < u.num_vars() and u.degree(k) == 0; ++k) {
158  /* do nothing */
159  }
160  //cout << "one base case: " << *ui << " and " << p << endl;
161  if (grading == nullptr) {
162  fac->set_coefficient(u.degree(k) - p.degree(k), -1);
163  prod->multiply_by(*fac);
164  fac->set_coefficient(u.degree(k) - p.degree(k), 0);
165  } else {
166  WT_TYPE d = grading[k];
167  fac->set_coefficient(d*(u.degree(k) - p.degree(k)), -1);
168  prod->multiply_by(*fac);
169  fac->set_coefficient(d*(u.degree(k) - p.degree(k)), 0);
170  }
171  }
172  delete fac;
174  prod->negate();
175  result->add(*prod);
176  delete(prod);
177  return result;
178 }
179 
180 list<Monomial>::const_iterator is_splitting_case(const list<Monomial> & T) {
181  list<Monomial>::const_iterator result = T.end(); // guilty until proven innocent
182  for (
183  list<Monomial>::const_iterator ti = T.begin();
184  result == T.end() and ti != T.end();
185  ++ti
186  ) {
187  // check whether other monomials are relatively prime to t
188  bool relprime = true;
189  for (
190  list<Monomial>::const_iterator ui = T.begin();
191  relprime and ui != T.end();
192  ++ui
193  ) {
194  if (ti != ui)
195  relprime = ti->is_coprime(*ui);
196  }
197  if (relprime)
198  result = ti;
199  }
200  return result;
201 }
202 
204  const list<Monomial> & T, list<Monomial>::const_iterator ui,
205  const WT_TYPE * grading
206 ) {
207  list<Monomial> U, V;
208  for (list<Monomial>::const_iterator ti = T.begin(); ti != T.end(); ++ti)
209  if (ti != ui)
210  U.push_back(*ti);
211  else
212  V.push_back(*ti);
214  Dense_Univariate_Integer_Polynomial * other = solve_one_monomial_case(V, grading);
215  result->multiply_by(*other);
216  delete other;
217  return result;
218 }
219 
220 Monomial choose_hilbert_pivot(const list<Monomial> & T) {
221  NVAR_TYPE n = T.front().num_vars();
222  unsigned * xcount = new unsigned [n] {0};
223  for (const Monomial & t : T)
224  for (NVAR_TYPE k = 0; k < n; ++k)
225  if (t.degree(k) != 0)
226  ++xcount[k];
227  int i = 0;
228  for (NVAR_TYPE k = 1; k < n; ++k)
229  if (xcount[k] > xcount[i])
230  i = k;
231  delete [] xcount;
232  unsigned * td = new unsigned [T.size()];
233  unsigned j = 0;
234  for (const Monomial & t : T)
235  if (t.degree(i) != 0)
236  td[j++] = t.degree(i);
237  unsigned m = j;
238  std::sort(td, td + m);
239  j = (m == 2) ? 0 : m / 2;
240  Monomial result(n);
241  result.set_exponent(i, td[j]);
242  delete [] td;
243  return result;
244 }
245 
247  const list<Monomial> & T, const WT_TYPE * grading
248 ) {
249  bool verbose = false;
250  if (verbose) {
251  cout << "T = { ";
252  for (const Monomial & t : T) cout << t << " ,";
253  cout << "}\n";
254  if (grading != nullptr) {
255  cout << "w = { ";
256  for (NVAR_TYPE i = 0; i < T.front().num_vars(); ++i)
257  cout << grading[i] << ", ";
258  cout << "}\n";
259  }
260  }
262  int i;
263  list<Monomial>::const_iterator ti;
264  if (T.size() == 1)
265  result = solve_one_monomial_case(T, grading);
266  else if (is_zero_base_case(T))
267  result = solve_zero_base_case(T, grading);
268  else if ((ti = is_one_base_case(T)) != T.end())
269  result = solve_one_base_case(T, ti, grading);
270  else if ((ti = is_splitting_case(T)) != T.end())
271  result = solve_splitting_case(T, ti, grading);
272  else {
274  if (verbose) cout << "pivot = " << p << endl;
275  // find pivot precisely
276  unsigned pi = 0;
277  while (p.degree(pi) == 0) { ++pi; }
278  list<Monomial> U, V;
279  for (const Monomial & t : T) {
280  if (not t.divisible_by(p))
281  U.push_back(t);
282  }
283  V = colon_ideal_without_ideals(T, p);
284  U.push_back(p);
285  if (verbose) {
286  cout << "U = { ";
287  for (const Monomial & u : U) cout << u << " ,";
288  cout << "}\n";
289  }
290  if (verbose) {
291  cout << "V = { ";
292  for (const Monomial & v : V) cout << v << " ,";
293  cout << "}\n";
294  }
295  result = hilbert_numerator_bigatti(V, grading);
296  if (verbose) cout << "result from V: " << *result << endl;
299  = hilbert_numerator_bigatti(U, grading);
300  if (verbose) cout << "result from U: " << *other << endl;
301  *result += *other;
302  delete other;
303  }
304  return result;
305 }
306 
308  NVAR_TYPE n,
310  const WT_TYPE * grading
311 ) {
314  unsigned r = 0;
315  if (grading == nullptr) {
316  NVAR_TYPE i = 0;
317  // perform synthetic division on the Hilbert numerator
318  for (/* */; r == 0 and i < n; ++i) {
319  COEF_TYPE a = hn->coeff(hn->degree());
322  for (DEG_TYPE j = hn->degree(); j != 0; --j) {
323  COEF_TYPE b = hn->coeff(j - 1);
324  a += b;
325  hn->set_coefficient(j - 1, a);
326  }
327  if ((r = hn->coeff(0)) != 0) {
328  delete hn;
329  hn = tmp;
330  } else {
331  delete tmp;
332  for (unsigned j = 0; j < hn->degree(); ++j)
333  hn->set_coefficient(j, hn->coeff(j+1));
334  hn->set_coefficient(hn->degree(), 0);
335  }
336  }
337  } else {
338  // perform long division (somewhat optimized) with max unused grading
339  // first find max grading
340  WT_TYPE curr_grad = grading[0];
341  NVAR_TYPE curr_grad_index = 0;
342  for (unsigned k = 1; k < n; ++k)
343  if (grading[k] > curr_grad) {
344  curr_grad = grading[k];
345  curr_grad_index = k;
346  }
347  // divide using max grading
348  for (NVAR_TYPE i = 1; hn->degree() != 0 and i < n; ++i) {
353  for (DEG_TYPE j = hn->degree(); j > curr_grad - 1; --j) {
354  COEF_TYPE a = hn->coeff(j);
355  q->set_coefficient(j - curr_grad, a);
356  hn->set_coefficient(j, 0);
357  hn->set_coefficient(j - curr_grad, hn->coeff(j - curr_grad) + a);
358  }
359  if (not hn->is_zero()) {
360  delete q; delete hn;
361  hn = tmp;
362  } else {
363  delete tmp; delete hn;
364  hn = q;
365  }
366  // find next larger gradient (or repeat if same occurs)
367  WT_TYPE tmp_grad = grading[0];
368  NVAR_TYPE tmp_grad_index = 0;
369  bool searching = true;
370  for (unsigned k = 0; searching and k < n; ++k) {
371  if (grading[k] == curr_grad and k > curr_grad_index) {
372  curr_grad_index = k;
373  searching = false;
374  }
375  else if (grading[k] > tmp_grad and grading[k] < curr_grad)
376  {
377  tmp_grad = grading[k];
378  tmp_grad_index = k;
379  }
380  }
381  curr_grad = tmp_grad;
382  curr_grad_index = tmp_grad_index;
383  }
384  }
385  return hn;
386 }
387 
389  NVAR_TYPE n,
392 ) {
393  return n - (h1->degree() - h2->degree());
394 }
395 
397  COEF_TYPE a, COEF_TYPE b
398 ) {
400  = new Dense_Univariate_Rational_Polynomial((b > 0) ? b : 1);
401  if (b == 0)
402  // p = 1
403  p->set_coefficient(0, 1, 1);
404  else {
405  // p = (t + a) / b
406  p->set_coefficient(0, a, b);
407  p->set_coefficient(1, 1, b);
408  // p = p * (t + a - i) / i for i = 1, ..., b
411  for (unsigned i = 1; i < b; ++i) {
412  q->set_coefficient(0, a - i, i);
413  q->set_coefficient(1, 1, i);
414  //cout << "a - i: " << a - i << " i: " << i << endl;
415  //cout << "p: " << *p << endl;
416  //cout << "q: " << *q << endl;
417  p->multiply_by(*q);
418  //cout << "p*q: " << *p << endl;
419  }
420  delete q;
421  }
422  return p;
423 }
424 
426  NVAR_TYPE n,
427  unsigned int pole_order,
428  const list<Monomial> T,
431 ) {
432  bool own_hn1 = false;
433  bool own_hn2 = false;
434  if (hn == nullptr) {
435  if (T.size() == 0)
436  return nullptr;
437  else {
438  own_hn1 = true;
440  }
441  }
442  if (hn2 == nullptr) {
443  own_hn2 = true;
444  hn2 = hilbert_second_numerator(n, hn);
445  }
446  if (pole_order == 0)
447  pole_order = n - (hn->degree() - hn2->degree());
449  = new Dense_Univariate_Rational_Polynomial(pole_order + 1);
450  if (pole_order != 0) {
451  DEG_TYPE d = hn2->degree();
452  COEF_TYPE d1 = pole_order - 1;
453  for (DEG_TYPE i = 0; i <= d; ++i) {
454  //q = polynomial_binomial(d1 - d + i, d1);
456  //q->scale_by(hn2->coeff(d - i));
457  q->scale_by(hn2->coeff(i));
458  hp->add(*q);
459  delete q;
460  }
461  }
462  if (pole_order % 2 != n % 2)
463  hp->negate();
464  if (own_hn1) delete hn;
465  if (own_hn2) delete hn2;
466  return hp;
467 }
468 
469 
470 #endif
DEG_TYPE total_degree(NVAR_TYPE m=0) const
Sum of exponents of the first m variables.
Definition: monomial.cpp:190
void set_coefficient(DEG_TYPE k, COEF_TYPE a)
set the coefficient of to
list< Monomial >::const_iterator is_one_base_case(const list< Monomial > &T)
test for the 1-base case
void set_coefficient(DEG_TYPE k, long a, unsigned long b)
set the coefficient of to
DEG_TYPE weighted_degree(const WT_TYPE *weights, NVAR_TYPE m=0) const
Definition: monomial.cpp:199
void multiply_by_monomial_of_degree(DEG_TYPE)
a hopefully efficient multiplication algorithm
Dense_Univariate_Rational_Polynomial * polynomial_binomial(long long a, long long b)
computes the number of combinations
Dense_Univariate_Rational_Polynomial * hilbert_polynomial(NVAR_TYPE n, unsigned int pole_order, const list< Monomial > T, Dense_Univariate_Integer_Polynomial *hn, Dense_Univariate_Integer_Polynomial *hn2)
computes the Hilbert polynomial for an ideal
void multiply_by(const Dense_Univariate_Rational_Polynomial &)
highly inefficient polynomial multiplication ( )
list< Monomial >::const_iterator is_splitting_case(const list< Monomial > &T)
test for the “splitting case”
Dense_Univariate_Integer_Polynomial * solve_one_base_case(const list< Monomial > &T, list< Monomial >::const_iterator ui, const WT_TYPE *grading)
applies Bigatti’s algorithm for the 1-base case
Dense_Univariate_Integer_Polynomial * hilbert_second_numerator(NVAR_TYPE n, Dense_Univariate_Integer_Polynomial *first, const WT_TYPE *grading)
computes the second Hilbert numerator (after reduction by )
void set_exponent(NVAR_TYPE i, DEG_TYPE e)
change th exponent to
Definition: monomial.cpp:78
COEF_TYPE coeff(DEG_TYPE k) const
the th coefficient
Dense_Univariate_Integer_Polynomial * hilbert_numerator_bigatti(const list< Monomial > &T, const WT_TYPE *grading)
the Bigatti algorithm to compute the Hilbert numerator
quick-’n-dirty Dense_Univariate integer polynomial class
void multiply_by(const Dense_Univariate_Integer_Polynomial &)
highly inefficient polynomial multiplication ( )
NVAR_TYPE num_vars() const
number of variables
Definition: monomial.hpp:130
Dense_Univariate_Integer_Polynomial * solve_zero_base_case(const list< Monomial > &T, const WT_TYPE *grading)
computes Hilbert numerator when the 0-base case applies
Implementation of monomials.
Definition: monomial.hpp:69
DEG_TYPE degree(NVAR_TYPE i) const
Degree of th variable.
Definition: monomial.cpp:183
Monomial choose_hilbert_pivot(const list< Monomial > &T)
chooses a pivot for the Bigatti algorithm
void add(const Dense_Univariate_Integer_Polynomial &q)
reasonably efficient, given our dense representation
DEG_TYPE degree() const
the polynomial’s degree (exponent of largest nonzero term)
void scale_by(COEF_TYPE a)
multiplies every monomial by a constant integer
quick-’n-dirty Dense_Univariate rational polynomial class
list< Monomial > colon_ideal_without_ideals(const list< Monomial > &U, const Monomial &t)
Computes the generators of an ideal and a new generator, given the ideal&#39;s generators. No monomial ideal machinery required.
Dense_Univariate_Integer_Polynomial * solve_splitting_case(const list< Monomial > &T, list< Monomial >::const_iterator ui, const WT_TYPE *grading)
applies Bigatti’s algorithm for the 1-base case
unsigned ideal_dimension(NVAR_TYPE n, const Dense_Univariate_Integer_Polynomial *h1, const Dense_Univariate_Integer_Polynomial *h2)
computes the dimension of the ideal by subtracting the Hilbert numerators
bool is_zero() const
returns True if and only if every valid coefficient is zero
bool is_zero_base_case(const list< Monomial > &T)
test for the 0-base case