Macaulay2 Engine
Loading...
Searching...
No Matches
gb-default.cpp
Go to the documentation of this file.
1/* Copyright 2003-2009, Michael E. Stillman */
2
3#include "gb-default.hpp"
4#include "text-io.hpp"
5
6#include "matrix.hpp"
7#include "matrix-con.hpp"
8#include "polyring.hpp"
9#include "newdelete.hpp"
10#include "relem.hpp"
11#include "hilb.hpp"
12
13#include "gbweight.hpp"
14#include "reducedgb.hpp"
15
16#include "monsort.hpp"
17
18#include "interrupted.hpp"
19
20#define PrintingDegree 0x0001
21
22#include <functional>
23#include <algorithm>
24#include <iostream>
25
27{
28 if (not over_ZZ()) return i;
29 int prev = i;
30 int next = forwardingZZ[i];
31 while (next != -1)
32 {
33 prev = next;
34 next = forwardingZZ[prev];
35 }
36 if (M2_gbTrace >= 16)
37 {
38 buffer o;
39 o << "resolve(" << i << ") = " << prev << newline;
40 std::cout << o.str() << std::endl;
41 }
42 return prev;
43}
44
45/*************************
46 * Initialization ********
47 *************************/
48
50{
51 exponents_t result = reinterpret_cast<exponents_t>(lcm_stash->new_elem());
52 return result;
53}
54
56 M2_bool collect_syz,
57 int n_rows_to_keep,
59 int strategy,
60 M2_bool use_max_degree_limit,
61 int max_degree_limit,
63{
64 (void) use_max_degree_limit;
65 (void) max_degree_limit;
66 const PolynomialRing *origR = m->get_ring()->cast_to_PolynomialRing();
67 if (origR == nullptr)
68 {
69 ERROR("ring is not a polynomial ring");
70 return nullptr;
71 }
72 if (origR->getMonoid()->numInvertibleVariables() > 0)
73 {
74 ERROR(
75 "cannot compute Groebner basis of ideal over a Laurent polynomial "
76 "ring, ie. with Inverses=>true");
77 return nullptr;
78 }
79 bool overZZ = origR->coefficient_type() == Ring::COEFF_ZZ;
80 bool isLocal = origR->getMonoid()->numNonTermOrderVariables() > 0;
81 if (overZZ and isLocal)
82 {
83 ERROR(
84 "Groebner bases in rings over ZZ with variables less than zero are "
85 "not yet supported");
86 return nullptr;
87 }
88
89 gbA *result = new gbA;
90 result->initialize(m,
91 collect_syz,
92 n_rows_to_keep,
94 strategy,
96 return result;
97}
98
99void gbA::initialize(const Matrix *m,
100 int csyz,
101 int nsyz,
102 M2_arrayint gb_weights0,
103 int strat,
104 int max_reduction_count0)
105{
106 // max_reduction_count: default was 10
107 // 1 is best possible for 3-anderbuch!
108 // 5 is: (114.64 sec, 494 MB)
109 // 10 is best so far (125.33 sec, 527 MB virtual).
110 // 50 is faster/smaller than 100, and 1000 was awful, on 3-andersbuch
111
112 ringtable = nullptr;
113 ringtableZZ = nullptr;
115
116 max_reduction_count = max_reduction_count0;
117
118 const PolynomialRing *origR = m->get_ring()->cast_to_PolynomialRing();
119 if (origR == nullptr)
120 {
121 ERROR("ring is not a polynomial ring");
122 // MES: throw an error here.
123 assert(0);
124 }
125 originalR = origR;
126 R = origR->get_gb_ring();
127 weightInfo_ = new GBWeight(m->rows(), gb_weights0);
128 gb_weights = weightInfo_->get_weights();
129
130 _nvars = R->get_flattened_monoid()->n_vars();
131 _coeff_type = origR->coefficient_type();
133
134 is_local_gb = (origR->getMonoid()->numNonTermOrderVariables() > 0);
135
136 spair_stash = new stash("gbA spairs", sizeof(spair));
137 gbelem_stash = new stash("gbA elems", sizeof(gbelem));
138 exp_size = EXPONENT_BYTE_SIZE(R->n_vars() + 2);
139 lcm_stash = new stash("gbA lead monoms", exp_size);
140
141 if (nsyz < 0 || nsyz > m->n_cols()) nsyz = m->n_cols();
142 n_rows_per_syz = nsyz;
143
144 _F = m->rows();
146
147 S = new SPairSet;
148 first_in_degree = 0;
149 n_syz = 0;
151 n_gens_left = 0;
152 n_subring = 0;
153
154 _strategy = strat;
155 _collect_syz = csyz;
156 _is_ideal = (_F->rank() == 1 && csyz == 0);
157 if (R->is_weyl_algebra()) _is_ideal = false;
158
159 use_hilb = false;
160 hilb_new_elems = false;
162 n_saved_hilb = 0;
163 hf_orig = nullptr;
164 hf_diff = nullptr;
165
166 this_degree = _F->lowest_primary_degree() - 1;
167 npairs = 0;
170
172 stats_ntail = 0;
173 stats_npairs = 0;
174 stats_ngb = 0;
175 stats_ngcd1 = 0;
176 stats_nretired = 0;
177
178 divisor_previous = -1;
180
181 // ZZZZ split
182 lookup = nullptr;
183 lookupZZ = nullptr;
184 if (over_ZZ())
185 lookupZZ = MonomialTableZZ::make(R->n_vars());
186 else
187 {
188 lookup = MonomialTable::make(R->n_vars());
189 }
190
192 minimal_gb_valid = true;
193
194 if (originalR->is_quotient_ring())
195 {
196 ringtable = originalR->get_quotient_MonomialTable();
197 ringtableZZ = originalR->get_quotient_MonomialTableZZ();
198
199 first_gb_element = originalR->n_quotients();
200 for (int i = 0; i < first_gb_element; i++)
201 {
202 gbvector *f = const_cast<gbvector *>(originalR->quotient_gbvector(i));
203 gbelem *g = gbelem_ring_make(f);
204 gb.push_back(g);
205 forwardingZZ.push_back(-1);
206 }
207 }
208 for (int i = 0; i < m->n_cols(); i++)
209 {
210 ring_elem denom;
211 gbvector *f = originalR->translate_gbvector_from_vec(_F, (*m)[i], denom);
212 spair *p = new_gen(i, f, denom);
213 if (p != nullptr)
214 {
216 }
217 }
218
219 state = STATE_NEWDEGREE; // will be changed if hilb fcn is used
222 ar_j = ar_i + 1;
224}
225
227{
228 gbvector *fsyz;
229
230 if (i < n_rows_per_syz)
231 fsyz = R->gbvector_term(_Fsyz, denom, i + 1);
232 else
233 fsyz = R->gbvector_zero();
234
235 if (R->gbvector_is_zero(f))
236 {
237 originalR->get_quotient_info()->gbvector_normal_form(_Fsyz, fsyz);
238 if (!R->gbvector_is_zero(fsyz))
239 {
240 // vec fsyzvec = _GR->gbvector_to_vec(_Fsyz,fsyz);
241 collect_syzygy(fsyz);
242 }
243 return nullptr;
244 }
245
246 POLY g;
247 g.f = f;
248 g.fsyz = fsyz;
249
250 return spair_make_gen(g);
251}
252
253/*************************
254 * GB removal ************
255 *************************/
256
257// We might not have to do ANYTHING here, since the garbage collector
258// will free everything up for us...
260{
261 // removes all allocated objects
262 for (int i = first_gb_element; i < gb.size(); i++)
263 if (gb[i])
264 {
265 R->gbvector_remove(gb[i]->g.f);
266 R->gbvector_remove(gb[i]->g.fsyz);
267 }
268 for (int i = 0; i < gb.size(); i++)
269 if (gb[i])
270 {
271 lcm_stash->delete_elem(gb[i]->lead);
272 gbelem_stash->delete_elem(gb[i]);
273 gb[i] = nullptr;
274 }
275 delete minimal_gb; // will free its own gbvector's.
276 for (int i = 0; i < _syz.size(); i++)
277 {
278 R->gbvector_remove(_syz[i]);
279 _syz[i] = nullptr;
280 }
281 delete lookup;
282 delete lookupZZ;
283 delete spair_stash;
284 delete gbelem_stash;
285 delete lcm_stash;
286 // Also remove the SPAirSet...
287}
288
290/*************************
291 * Exponent handling *****
292 *************************/
293
294static void exponents_lcm(int nvars,
295 int dega,
296 exponents_t a,
297 exponents_t b,
299 M2_arrayint weights,
300 int &result_degree)
301// can handle the case when a == result or b == result
302{
303 int i;
304 int deg = dega;
305 for (i = 0; i < nvars; i++)
306 {
307 int diff = b[i] - a[i];
308 if (diff <= 0)
309 result[i] = a[i];
310 else
311 {
312 result[i] = b[i];
313 deg += diff * weights->array[i];
314 }
315 }
316 result_degree = deg;
317}
318
319static bool exponents_equal(int nvars, exponents_t a, exponents_t b)
320{
321 for (int i = 0; i < nvars; i++)
322 if (a[i] != b[i]) return false;
323 return true;
324}
325
326static bool exponents_divide(int nvars, exponents_t a, exponents_t b)
327{
328 for (int i = 0; i < nvars; i++)
329 if (a[i] > b[i]) return false;
330 return true;
331}
332
333static bool exponents_less_than(int nvars, exponents_t a, exponents_t b)
334{
335 for (int i = 0; i < nvars; i++)
336 {
337 if (a[i] < b[i]) return true;
338 if (a[i] > b[i]) return false;
339 }
340 return false;
341}
342
343/*************************
344 * gbelem handling *******
345 *************************/
346
348{
349 int f_leadweight;
350 gbelem *g = reinterpret_cast<gbelem *>(gbelem_stash->new_elem());
351 g->g.f = f;
352 g->g.fsyz = nullptr;
353 g->lead = exponents_make();
354 R->gbvector_get_lead_exponents(_F, f, g->lead);
355 g->deg = weightInfo_->gbvector_weight(f, f_leadweight);
356 g->gap = g->deg - f_leadweight;
357 g->size = R->gbvector_n_terms(f);
359 return g;
360}
361
363 gbvector *fsyz, // grabs fsyz
364 gbelem_type minlevel,
365 int deg)
366{
367 int f_leadweight;
368 gbelem *g = reinterpret_cast<gbelem *>(gbelem_stash->new_elem());
369 g->g.f = f;
370 g->g.fsyz = fsyz;
371 g->lead = exponents_make();
372 R->gbvector_get_lead_exponents(_F, f, g->lead);
373 g->deg = deg;
374 weightInfo_->gbvector_weight(f, f_leadweight); // return value not used
375 g->gap = deg - weightInfo_->gbvector_term_weight(f);
376 if (f->next == nullptr) // a monomial. This is a hack: we should lower the gap
377 // value when we can.
378 // the problem though is that this sometimes slows down the computation
379 // dramatically.
380 g->gap = 0;
381 g->size = R->gbvector_n_terms(f);
382 g->minlevel = minlevel;
383 return g;
384}
385
387{
388 gbelem *gnew = reinterpret_cast<gbelem *>(gbelem_stash->new_elem());
389
390 gnew->g.f = R->gbvector_copy(g->g.f);
391 gnew->g.fsyz = R->gbvector_copy(g->g.fsyz);
392 gnew->lead = exponents_make();
393 for (int i = 0; i < _nvars; i++) gnew->lead[i] = g->lead[i];
394 gnew->deg = g->deg;
395 gnew->minlevel = g->minlevel;
396 return g;
397}
398
399void gbA::gbelem_text_out(buffer &o, int i, int nterms) const
400{
401 if (!gb[i])
402 {
403 o << "removed";
404 }
405 else
406 {
407 gbelem_type minlevel = gb[i]->minlevel;
408 bool ismingen = (minlevel & ELEM_MINGEN);
409 bool ismingb = (minlevel & ELEM_MINGB);
410 if (ismingb)
411 o << "GB elem: ";
412 else
413 o << "reducer: ";
414 o << "g" << i << " = ";
415 R->gbvector_text_out(o, _F, gb[i]->g.f, nterms);
416 o << " ["
417 << "gap " << gb[i]->gap << " size " << gb[i]->size << " deg "
418 << gb[i]->deg;
419 if (ismingen) o << " mingen";
420 o << "]";
421 }
422}
423
424/*************************
425 * SPair handling ********
426 *************************/
427
429{
430 spair *result = reinterpret_cast<spair *>(spair_stash->new_elem());
431 result->next = nullptr;
432 result->lead_of_spoly = nullptr;
433 return result;
434}
435
437{
438 if (p == nullptr) return;
439 if (p->type == SPAIR::SPAIR_GEN || p->type == SPAIR::SPAIR_ELEM)
440 {
441 R->gbvector_remove(p->x.f.f);
442 R->gbvector_remove(p->x.f.fsyz);
443 }
444 R->gbvector_remove(p->lead_of_spoly);
445 lcm_stash->delete_elem(p->lcm);
446 spair_stash->delete_elem(p);
447}
448
450{
451 gbelem *g1 = gb[i];
452 gbelem *g2 = gb[j];
453 exponents_t exp1 = g1->lead;
454 exponents_t exp2 = g2->lead;
456 result->next = nullptr;
458 result->lcm = exponents_make();
460 _nvars, g1->deg, exp1, exp2, result->lcm, gb_weights, result->deg);
461 if (g2->gap > g1->gap) result->deg += g2->gap - g1->gap;
462 result->x.pair.i = i;
463 result->x.pair.j = j;
464
465 return result;
466}
467
469{
470 spair *result = spair_make(i, j);
472 return result;
473}
474
476{
477 assert(f.f != 0);
479 R->gbvector_get_lead_exponents(_F, f.f, exp1);
480 int deg = weightInfo_->gbvector_weight(f.f);
482 result->next = nullptr;
483 result->type = SPAIR::SPAIR_GEN;
484 result->deg = deg;
485 result->lcm = exp1;
486 result->x.f = f;
487
488 return result;
489}
490
492{
493 spair *result;
494 int j;
495 gbelem *g1 = gb[i];
496 exponents_t exp1 = g1->lead;
498 int vvar = R->skew_variable(v);
499 for (j = 0; j < _nvars; j++) exp2[j] = 0;
500 exp2[vvar] = 2;
501 result = spair_node();
502 result->next = nullptr;
504 result->lcm = exp2;
505 exponents_lcm(_nvars, g1->deg, exp1, exp2, exp2, gb_weights, result->deg);
506 result->x.pair.i = i;
507 result->x.pair.j = v;
508
509 return result;
510}
511
513{
514 /* This requires that j indexes into the gb array somewhere. */
515 spair *result = spair_make(i, j);
517
518 return result;
519}
520
522{
523 const int N = 1000;
524 char s[N]; // enough room for all of the non polynomial cases.
525 switch (p->type)
526 {
528 snprintf(s, N, "spairgcd(g%d,g%d)", p->x.pair.j, p->x.pair.i);
529 o << s;
530 snprintf(s, N, " deg(%d)", p->deg);
531 o << s;
532 o << " lcm[";
533 for (int i = 0; i < _nvars + 2; i++)
534 {
535 snprintf(s, N, "%d ", p->lcm[i]);
536 o << s;
537 }
538 o << "]";
539 break;
541 snprintf(s, N, "spair(g%d,g%d):", p->x.pair.j, p->x.pair.i);
542 o << s;
543 snprintf(s, N, " deg %d", p->deg);
544 o << s;
545 o << " lcm exponents [";
546 for (int i = 0; i < _nvars + 2; i++)
547 {
548 snprintf(s, N, "%d ", p->lcm[i]);
549 o << s;
550 }
551 o << "]";
552 break;
553 case SPAIR::SPAIR_GEN:
554 o << "generator ";
555 R->gbvector_text_out(o, _F, p->f(), 3);
556 break;
558 o << "elem ";
559 R->gbvector_text_out(o, _F, p->f(), 3);
560 break;
562 snprintf(s, N, "rpair(%d,%d)", p->x.pair.i, p->x.pair.j);
563 o << s;
564 break;
566 snprintf(s, N, "skewpair(g%d,g%d)", p->x.pair.j, p->x.pair.i);
567 o << s;
568 break;
569 default:
570 o << "unknown pair";
571 break;
572 }
573}
574
575/*************************
576 * S-pair heuristics *****
577 *************************/
578
579#ifdef __has_feature // a Clang and maybe gcc extension to determine compiler features
580 #if __has_feature(thread_sanitizer)
581 #define __SANITIZE_THREAD__ 1 // gcc predefines this instead of __has_feature
582 #endif
583#endif
584
585#if __SANITIZE_THREAD__ // to avoid warnings; these variables are only used for diagnostics
586static std::atomic_ulong ncalls(0);
587static std::atomic_ulong nloops(0);
588static std::atomic_ulong nsaved_unneeded(0);
589#else
590static unsigned long ncalls = 0;
591static unsigned long nloops = 0;
592static unsigned long nsaved_unneeded = 0;
593#endif
595{
596 /* Check the criterion: in(m) divides lcm(p).
597 * If so: check if lcm(p1,m) == lcm(p) (if so, return false)
598 * check if lcm(p2,m) == lcm(p) (if so, return false)
599 * If still here, return true.
600 */
601 int i, first, second;
602 bool firstok;
603 exponents_t mexp, lcm, p1exp, p2exp;
604 if (p->type != SPAIR::SPAIR_SPAIR && p->type != SPAIR::SPAIR_RING)
605 return false;
606 mexp = m->lead;
607 lcm = p->lcm;
608 if (gbelem_COMPONENT(m) != spair_COMPONENT(p)) return false;
609
610 first = p->x.pair.i;
611 second = p->x.pair.j;
612 p1exp = gb[first]->lead;
613 p2exp =
614 gb[second]->lead; /* If a ring pair, this should index into gb array */
615
616 ncalls++;
617 for (i = 0; i < _nvars; i++, nloops++)
618 if (mexp[i] > lcm[i]) return false;
619
620 firstok = false;
621 for (i = 0; i < _nvars; i++)
622 {
623 if (mexp[i] == lcm[i]) continue;
624 if (p1exp[i] == lcm[i]) continue;
625 firstok = true;
626 break;
627 }
628 if (!firstok) return false;
629 for (i = 0; i < _nvars; i++)
630 {
631 if (mexp[i] == lcm[i]) continue;
632 if (p2exp[i] == lcm[i]) continue;
633 return true;
634 }
635 return false;
636}
637
639{
640 /* Removes all pairs from C->S that are not needed */
641 if (over_ZZ()) return;
642 spair head;
643 spair *p = &head;
644 gbelem *m = gb[id];
645
646 head.next = S->heap;
647 while (p->next != nullptr)
648 if (pair_not_needed(p->next, m))
649 {
651 spair *tmp = p->next;
652 p->next = tmp->next;
653 tmp->next = nullptr;
654 if (M2_gbTrace >= 10)
655 {
656 buffer o;
657 o << "removing unneeded ";
658 spair_text_out(o, tmp);
659 emit_line(o.str());
660 }
661 spair_delete(tmp);
662 S->nelems--;
663 }
664 else
665 p = p->next;
666 S->heap = head.next;
667}
668
670{
671 int i, j;
672 exponents_t e1, e2;
673 if (p->type != SPAIR::SPAIR_SPAIR) return false;
674 i = p->x.pair.i;
675 j = p->x.pair.j;
676 e1 = gb[i]->lead;
677 e2 = gb[j]->lead;
678 for (i = 0; i < _nvars; i++)
679 if (e1[i] > 0 && e2[i] > 0) return false;
680 return true;
681}
682
683gbA::spairs::iterator gbA::choose_pair(gbA::spairs::iterator first,
684 gbA::spairs::iterator next)
685{
686 /* a is an array of spair's, and a[first], ..., a[next-1] all have the
687 same lcm, which is a minimal monomial generator of all such lcm's.
688 Our goal is to choose a nice one, and throw away the others.
689 We return one spair, and delete the rest.
690 */
691 if (next == first + 1) return first;
692 return first; /* MES: really do something here... */
693}
694
695namespace {
696struct spair_sorter
697{
698 int nvars;
699 spair_sorter(int nv) : nvars(nv) {}
700 bool operator()(gbA::spair *a, gbA::spair *b)
701 {
702 /* Compare using degree, then type, then lcm */
703 bool result;
704 int cmp = a->deg - b->deg;
705 if (cmp < 0)
706 result = true;
707 else if (cmp > 0)
708 result = false;
709 else
710 {
711 cmp = a->type - b->type;
712 if (cmp < 0)
713 result = true;
714 else if (cmp > 0)
715 result = false;
716 else
717 result = exponents_less_than(nvars, a->lcm, b->lcm);
718 }
719 return result;
720 }
721};
722}; // unnamed namespace
723
739{
740 public:
742
743 private:
744 const FreeModule *F;
746
747 public:
749 {
750 // returns: LT if a < b, EQ if a == b, GT if a > b.
751 /* Compare using degree, then type, then lead term of spoly */
752 int result;
753 int cmp = a->deg - b->deg;
754 if (cmp < 0)
755 result = GT;
756 else if (cmp > 0)
757 result = LT;
758 else
759 {
760 gbvector *a1 =
761 (a->type > gbA::SPAIR::SPAIR_SKEW ? a->f() : a->lead_of_spoly);
762 gbvector *b1 =
763 (b->type > gbA::SPAIR::SPAIR_SKEW ? b->f() : b->lead_of_spoly);
764 if (a1 == nullptr)
765 {
766 if (b1 == nullptr)
767 result = EQ;
768 else
769 result = LT;
770 }
771 else
772 {
773 if (!b1)
774 result = GT;
775 else
776 result = R->gbvector_compare(F, a1, b1);
777 }
778 }
779 return result;
780 }
781
782 bool operator()(value a, value b) { return compare(a, b) == LT; }
783 SPolySorter(GBRing *R0, const FreeModule *F0) : F(F0), R(R0) {}
785};
786
787// ZZZZ split
788void gbA::minimalize_pairs_non_ZZ(spairs &new_set)
789/* new_set: array of spair* */
790{
791#if 0
792// spairs keep_for_now;
793// emit("--minimalize pairs--\n");
794// for (int i=0; i<new_set.size(); i++) {
795// keep_for_now.push_back(new_set[i]);
796// debug_spair(new_set[i]);
797// }
798#endif
799 std::stable_sort(new_set.begin(), new_set.end(), spair_sorter(_nvars));
801
802 // array_sort(new_set, (compareFcn)spair_compare, 0);
803 spairs::iterator first = new_set.begin();
804 spairs::iterator next = first;
805 spairs::iterator end = new_set.end();
806 for (; first != end; first = next)
807 {
808 next = first + 1;
809 spair *me = *first;
810 while (next != end)
811 {
812 spair *p = *next;
813 if (!exponents_equal(_nvars, me->lcm, p->lcm)) break;
814 next++;
815 }
816 /* At this point: [first,next) is the range of equal monomials */
817
818 int inideal = montab->find_divisors(1, me->lcm, 1);
819 if (inideal == 0)
820 {
821 spairs::iterator t = choose_pair(first, next);
822 spair *p = *t;
824 {
825 stats_ngcd1++;
826 if ((M2_gbTrace & PRINT_SPAIR_TRACKING) != 0)
827 {
828 buffer o;
829 o << "removing spair because of gcd: ";
830 spair_text_out(o, p);
831 emit_line(o.str());
832 }
834 }
835 else
836 {
837 if (M2_gbTrace >= 4)
838 {
839 buffer o;
840 o << " new ";
841 spair_text_out(o, p);
842 emit_line(o.str());
843 }
845 montab->insert(p->lcm, 1, 0);
846 }
847 *t = 0;
848 }
849 }
850
851 delete montab;
852 for (spairs::iterator i = new_set.begin(); i != new_set.end(); i++)
853 spair_delete(*i);
854}
855
856void gbA::minimalize_pairs_ZZ(spairs &new_set)
857{
858 // Prune down the set of spairs to a 'minimal' set. For each one, we
859 // need to add in a "gcd" combination spair as well.
860
861 VECTOR(mpz_srcptr) coeffs;
862 VECTOR(mpz_srcptr) coeffs2;
863 VECTOR(exponents_t) exps;
864 VECTOR(int) comps;
865 VECTOR(int) positions;
866
867 coeffs.reserve(gb.size());
868 coeffs2.reserve(gb.size());
869 exps.reserve(gb.size());
870 comps.reserve(gb.size());
871
872 for (VECTOR(spair *)::iterator i = new_set.begin(); i != new_set.end(); i++)
873 {
874 spair *a = *i;
875 exps.push_back(a->lcm);
876 comps.push_back(1); /* This is not needed here, as all of these
877 have the same component */
878 /* Now get the coefficient */
879 /* This is the lcm divided by the lead coeff, but it depends on the kind
880 * of spair */
881 if (a->type == SPAIR::SPAIR_SKEW)
882 {
883 coeffs.push_back(globalZZ->one().get_mpz());
884 coeffs2.push_back(nullptr); // will never be referred to below
885 }
886 else
887 {
888 /* */
889 gbvector *f1 = gb[a->x.pair.i]->g.f;
890 gbvector *f2 = gb[a->x.pair.j]->g.f;
891 ring_elem u, v;
892 globalZZ->syzygy(f1->coeff, f2->coeff, u, v);
893 coeffs.push_back(u.get_mpz());
894 coeffs2.push_back(v.get_mpz());
895
896 if (mpz_cmpabs_ui(u.get_mpz(), 1) && mpz_cmpabs_ui(v.get_mpz(), 1))
897 {
898 spair *p2 = spair_make_gcd_ZZ(a->x.pair.i, a->x.pair.j);
899 if (M2_gbTrace >= 4)
900 {
901 buffer o;
902 o << " creating ";
903 spair_text_out(o, p2);
904 emit_line(o.str());
905 }
907 }
908 }
909 }
910
911 if (_strategy == 0)
913 _nvars, coeffs, exps, comps, positions);
914 else
916 _nvars, coeffs, exps, comps, positions, true);
917
918 for (VECTOR(int)::iterator i = positions.begin(); i != positions.end(); i++)
919 {
920 // Insert this spair, and also the corresponding gcd one.
921 spair *p = new_set[*i];
922 if (M2_gbTrace >= 4)
923 {
924 buffer o;
925 o << " creating ";
926 spair_text_out(o, p);
927 emit_line(o.str());
928 }
930#if 0
931 mpz_ptr u = coeffs[*i];
932 mpz_ptr v = coeffs2[*i];
933 if (p->type != SPAIR::SPAIR_SKEW && mpz_cmpabs_ui(u,1) && mpz_cmpabs_ui(v,1))
934 {
935 spair *p2 = spair_make_gcd_ZZ(p->x.pair.i, p->x.pair.j);
936 if (M2_gbTrace >= 4)
937 {
938 buffer o;
939 spair_text_out(o, p2);
940 emit_line(o.str());
941 }
943 }
944#endif
945 }
946}
947
948void gbA::minimalize_pairs(spairs &new_set)
949{
950 if (over_ZZ())
951 minimalize_pairs_ZZ(new_set);
952 else
954}
955
957{
958 assert(gb[id] != nullptr);
959 gbelem *r = gb[id];
960 int x = gbelem_COMPONENT(r);
961
962 /* Step 1. Remove un-needed old pairs */
964
965 /* Step 2. Collect new pairs */
966 spairs new_set;
967
968 /* Step 2a: */
969 if (R->is_skew_commutative())
970 {
971 for (int i = 0; i < R->n_skew_commutative_vars(); i++)
972 if (r->lead[R->skew_variable(i)] > 0)
973 {
974 spair *s = spair_make_skew(id, i);
975 new_set.push_back(s);
976 }
977 }
978 /* Step 2b: pairs from ring elements, or 'in stone' elements */
979 for (int i = 0; i < first_gb_element; i++)
980 {
981 spair *s = spair_make_ring(id, i);
982 new_set.push_back(s);
983 }
984 /* Step 2c. pairs from the vectors themselves */
985 /* Loop through the minimal GB elements and form the s-pair */
986 for (int i = first_gb_element; i < id; i++)
987 {
988 gbelem *g = gb[i];
989 if (g && (g->minlevel & ELEM_MINGB) && gbelem_COMPONENT(g) == x)
990 {
991 spair *s = spair_make(id, i);
992 new_set.push_back(s);
993 }
994 }
995
996 /* Step 3. Minimalize this set */
998 new_set); /* Modifies new_set, inserts minimal pairs into S */
999}
1000
1001/*************************
1002 * S-pair sets ***********
1003 *************************/
1004
1006 : nelems(0),
1007 n_in_degree(0),
1008 heap(nullptr),
1009 n_computed(0),
1010 spair_list(nullptr),
1011 spair_last_deferred(nullptr),
1012 gen_list(nullptr),
1013 gen_last_deferred(nullptr)
1014{
1015}
1016
1018{
1019 while (!set)
1020 {
1021 spair *tmp = set;
1022 set = set->next;
1023 spair_delete(tmp);
1024 }
1025 set = nullptr;
1026}
1027
1029{
1030 remove_spair_list(S->heap);
1031 remove_spair_list(S->spair_list);
1032 remove_spair_list(S->spair_deferred_list.next);
1033 remove_spair_list(S->gen_list);
1034 remove_spair_list(S->gen_deferred_list.next);
1035 S->spair_last_deferred = nullptr;
1036 S->gen_last_deferred = nullptr;
1037}
1038
1040/* Insert a LIST of s pairs into S */
1041{
1042 while (p != nullptr)
1043 {
1044 if (p->type == SPAIR::SPAIR_GEN) n_gens_left++;
1046 spair *tmp = p;
1047 p = p->next;
1048 S->nelems++;
1049 tmp->next = S->heap;
1050 S->heap = tmp;
1051 }
1052}
1053
1055/* Removes the next element of the current degree, returning NULL if none left
1056 */
1057{
1058 spair *result = S->spair_list;
1059 if (result)
1060 {
1061 S->spair_list = result->next;
1062 }
1063 else
1064 {
1065 if (S->spair_deferred_list.next != nullptr)
1066 {
1067 if (M2_gbTrace >= 4)
1068 {
1069 emit_line("considering deferred pairs: ");
1070 }
1071 S->spair_list = S->spair_deferred_list.next;
1072 S->spair_deferred_list.next = nullptr;
1073 S->spair_last_deferred = &S->spair_deferred_list;
1074 result = S->spair_list;
1075 S->spair_list = result->next;
1076 }
1077 else
1078 {
1079 // Now do the same for generators
1080 result = S->gen_list;
1081 if (result)
1082 {
1083 S->gen_list = result->next;
1084 }
1085 else
1086 {
1087 if (S->gen_deferred_list.next != nullptr)
1088 {
1089 if (M2_gbTrace >= 4)
1090 {
1091 emit_line(" deferred gen pairs: ");
1092 }
1093 S->gen_list = S->gen_deferred_list.next;
1094 S->gen_deferred_list.next = nullptr;
1095 S->gen_last_deferred = &S->gen_deferred_list;
1096 result = S->gen_list;
1097 S->gen_list = result->next;
1098 }
1099 else
1100 return nullptr;
1101 }
1102 }
1103 }
1104
1105 result->next = nullptr;
1106 S->nelems--;
1107 S->n_in_degree--;
1108 S->n_computed++;
1109 if (result->type == SPAIR::SPAIR_GEN) n_gens_left--;
1110 return result;
1111}
1112
1114// Defer the spair p until later in this same degree
1115// The spair should have been reduced a number of times
1116// already, so its type should be SPAIR::SPAIR_GEN or SPAIR::SPAIR_ELEM
1117{
1118 if (M2_gbTrace == 15)
1119 {
1120 emit_line(" deferred by reduction count");
1121 }
1122 else if (M2_gbTrace >= 4)
1123 emit_wrapped("D");
1124 // spair_delete(p); // ONLY FOR TESTING!! THIS IS INCORRECT!!
1125 // return;
1126 S->n_in_degree++;
1127 if (p->type == SPAIR::SPAIR_GEN)
1128 {
1129 S->gen_last_deferred->next = p;
1130 S->gen_last_deferred = p;
1131 n_gens_left++;
1132 }
1133 else
1134 {
1135 S->spair_last_deferred->next = p;
1136 S->spair_last_deferred = p;
1137 }
1138}
1139
1141{
1142 spair *p;
1143 int nextdeg;
1144 int len = 1;
1145 if (S->heap == nullptr) return 0;
1146 nextdeg = S->heap->deg;
1147 for (p = S->heap->next; p != nullptr; p = p->next)
1148 if (p->deg > nextdeg)
1149 continue;
1150 else if (p->deg < nextdeg)
1151 {
1152 len = 1;
1153 nextdeg = p->deg;
1154 }
1155 else
1156 len++;
1157 nextdegree = nextdeg;
1158 return len;
1159}
1160
1162/* Finds the next degree to consider, returning the number of spairs in that
1163 * degree */
1164{
1165 S->spair_list = nullptr;
1166 S->spair_deferred_list.next = nullptr;
1167 S->spair_last_deferred = &S->spair_deferred_list;
1168
1169 S->gen_list = nullptr;
1170 S->gen_deferred_list.next = nullptr;
1171 S->gen_last_deferred = &S->gen_deferred_list;
1172
1173 int len = spair_set_determine_next_degree(nextdegree);
1174 if (len == 0) return 0;
1175
1176 spair head;
1177 spair *p;
1178 head.next = S->heap;
1179 p = &head;
1180 while (p->next != nullptr)
1181 if (p->next->deg != nextdegree)
1182 p = p->next;
1183 else
1184 {
1185 spair *tmp = p->next;
1186 p->next = tmp->next;
1187 if (tmp->type == SPAIR::SPAIR_GEN)
1188 {
1189 tmp->next = S->gen_list;
1190 S->gen_list = tmp;
1191 }
1192 else
1193 {
1194 // All other types are on the spair list
1195 tmp->next = S->spair_list;
1196 S->spair_list = tmp;
1197 }
1198 }
1199 S->heap = head.next;
1200 S->n_in_degree = len;
1201
1202 /* Now sort 'spair_list' and 'gen_list'. */
1203 spairs_sort(len, S->spair_list);
1204 spairs_sort(len, S->gen_list);
1205 // G->spairs_reverse(S->spair_list);
1206 // G->spairs_reverse(S->gen_list);
1207 return len;
1208}
1209
1212{
1213 spair *reversed = nullptr;
1214 spair *p = ps;
1215 while (p != nullptr)
1216 {
1217 spair *tmp = p;
1218 p = p->next;
1219 tmp->next = reversed;
1220 reversed = tmp;
1221 }
1222 ps = reversed;
1223}
1224
1225/* Sorting a list of spairs */
1226void gbA::spairs_sort(int len, spair *&ps)
1227{
1228 if (ps == nullptr || ps->next == nullptr) return;
1229 if (len <= 1) return;
1230 spairs a; // array of spair's
1231 spairs b; // these are the ones which are uncomputed, but whose lead_of_spoly
1232 // is 0.
1233 a.reserve(len);
1234 for (spair *p = ps; p != nullptr; p = p->next)
1235 {
1236 if ((p->type > SPAIR::SPAIR_SKEW) || p->lead_of_spoly)
1237 a.push_back(p);
1238 else
1239 b.push_back(p);
1240 }
1241
1242 SPolySorter SP(R, _F);
1243 // QuickSorter<SPolySorter>::sort(&SP,&a[0],a.size());
1244 std::stable_sort(a.begin(), a.end(), SP);
1245 int asize = INTSIZE(a);
1246 int bsize = INTSIZE(b);
1247
1248 if (asize > 0)
1249 {
1250 ps = a[0];
1251 for (int i = 1; i < asize; i++) a[i - 1]->next = a[i];
1252 }
1253 else if (bsize > 0)
1254 {
1255 ps = b[0];
1256 // debugging// fprintf(stderr, "bsize is %d\n",bsize);
1257 }
1258 else
1259 {
1260 ps = nullptr;
1261 return;
1262 }
1263
1264 if (asize > 0) a[asize - 1]->next = (bsize > 0 ? b[0] : nullptr);
1265 if (bsize > 0)
1266 {
1267 for (int i = 1; i < bsize; i++) b[i - 1]->next = b[i];
1268 b[bsize - 1]->next = nullptr;
1269 }
1270}
1271
1272/****************************************
1273 * Polynomial arithmetic and reduction **
1274 ****************************************/
1275
1277{
1278 gbvector *ltsyz = nullptr;
1279 POLY f, g;
1280 if (p->type > SPAIR::SPAIR_SKEW)
1281 {
1282 R->gbvector_remove(p->lead_of_spoly);
1283 p->lead_of_spoly = nullptr;
1284 return;
1285 }
1286 f = gb[p->x.pair.i]->g;
1287 if (p->type == SPAIR::SPAIR_SKEW)
1288 {
1289 const int *mon = R->skew_monomial_var(p->x.pair.j);
1290 R->gbvector_mult_by_term(
1291 _F, _Fsyz, R->one(), mon, f.f, nullptr, p->lead_of_spoly, ltsyz);
1292 }
1293 else if (p->type == SPAIR::SPAIR_GCD_ZZ)
1294 {
1295 g = gb[p->x.pair.j]->g;
1296 R->gbvector_combine_lead_terms_ZZ(
1297 _F, _Fsyz, f.f, nullptr, g.f, nullptr, p->lead_of_spoly, ltsyz);
1298 }
1299 else
1300 {
1301 g = gb[p->x.pair.j]->g;
1302 R->gbvector_cancel_lead_terms(
1303 _F, _Fsyz, f.f, nullptr, g.f, nullptr, p->lead_of_spoly, ltsyz);
1304 }
1305 if (p->lead_of_spoly != nullptr)
1306 {
1307 gbvector *tmp = p->lead_of_spoly->next;
1308 p->lead_of_spoly->next = nullptr;
1309 R->gbvector_remove(tmp);
1310 }
1311}
1312
1314{
1315 POLY f, g;
1316 int i, j;
1317 if (M2_gbTrace >= 5 && M2_gbTrace != 15)
1318 {
1319 buffer o;
1320 spair_text_out(o, p);
1321 emit_line(o.str());
1322 }
1323 if (p->type > SPAIR::SPAIR_SKEW) return;
1324 R->gbvector_remove(p->lead_of_spoly);
1325 p->lead_of_spoly = nullptr;
1326 i = get_resolved_gb_index(p->x.pair.i);
1327 f = gb[i]->g;
1328 if (p->type == SPAIR::SPAIR_SKEW)
1329 {
1330 const int *mon = R->skew_monomial_var(p->x.pair.j);
1331 R->gbvector_mult_by_term(
1332 _F, _Fsyz, R->one(), mon, f.f, f.fsyz, p->f(), p->fsyz());
1333 }
1334 else if (p->type == SPAIR::SPAIR_GCD_ZZ)
1335 {
1336 j = get_resolved_gb_index(p->x.pair.j);
1337 g = gb[j]->g;
1338 R->gbvector_combine_lead_terms_ZZ(
1339 _F, _Fsyz, f.f, f.fsyz, g.f, g.fsyz, p->f(), p->fsyz());
1340 }
1341 else
1342 {
1343 j = get_resolved_gb_index(p->x.pair.j);
1344 g = gb[j]->g;
1345 R->gbvector_cancel_lead_terms(
1346 _F, _Fsyz, f.f, f.fsyz, g.f, g.fsyz, p->f(), p->fsyz());
1347 }
1348 p->type = SPAIR::SPAIR_ELEM;
1349 if (M2_gbTrace >= 5 && M2_gbTrace != 15)
1350 {
1351 buffer o;
1352 o << " ";
1353 R->gbvector_text_out(o, _F, p->f());
1354 emit_line(o.str());
1355 }
1356}
1357
1358// ZZZZ split
1360{
1361 /* Returns false iff we defer computing this spair. */
1362 /* If false is returned, this routine has grabbed the spair 'p'. */
1363 int tmf, wt;
1364 int count = -1;
1365
1367
1368 if (M2_gbTrace == 15)
1369 {
1370 buffer o;
1371 o << "considering ";
1372 spair_text_out(o, p);
1373 o << " : ";
1374 emit_line(o.str());
1375 }
1376 compute_s_pair(p); /* Changes the type, possibly */
1377
1378 while (!R->gbvector_is_zero(p->f()))
1379 {
1380 if (count++ > max_reduction_count)
1381 {
1383 return false;
1384 }
1385 if (M2_gbTrace >= 5)
1386 {
1387 if ((wt = weightInfo_->gbvector_weight(p->f(), tmf)) > this_degree)
1388 {
1389 buffer o;
1390 o << "ERROR: degree of polynomial is too high: deg " << wt
1391 << " termwt " << tmf << " expectedeg " << this_degree
1392 << newline;
1393 emit(o.str());
1394 }
1395 }
1396
1397 int gap, w;
1398 R->gbvector_get_lead_exponents(_F, p->f(), EXP);
1399 int x = p->f()->comp;
1400 w = find_good_divisor(EXP, x, this_degree, gap);
1401
1402 // replaced gap, g.
1403 if (w < 0) break;
1404 if (gap > 0)
1405 {
1406 POLY h;
1407 h.f = R->gbvector_copy(p->x.f.f);
1408 h.fsyz = R->gbvector_copy(p->x.f.fsyz);
1409 insert_gb(h, (p->type == SPAIR::SPAIR_GEN ? ELEM_MINGEN : 0));
1410 }
1411 POLY g = gb[w]->g;
1412
1413 R->gbvector_reduce_lead_term(_F,
1414 _Fsyz,
1415 nullptr,
1416 p->f(),
1417 p->fsyz(), /* modifies these */
1418 g.f,
1419 g.fsyz);
1420
1422 if (M2_gbTrace == 15)
1423 {
1424 buffer o;
1425 o << " reducing by g" << w;
1426 o << ", yielding ";
1427 R->gbvector_text_out(o, _F, p->f(), 3);
1428 emit_line(o.str());
1429 }
1430 if (R->gbvector_is_zero(p->f())) break;
1431 if (gap > 0)
1432 {
1433 p->deg += gap;
1434 if (M2_gbTrace == 15)
1435 {
1436 buffer o;
1437 o << " deferring to degree " << p->deg;
1438 emit_line(o.str());
1439 }
1441 return false;
1442 }
1443 }
1444 if (M2_gbTrace >= 4 && M2_gbTrace != 15)
1445 {
1446 buffer o;
1447 o << "." << count;
1448 emit_wrapped(o.str());
1449 }
1450 return true;
1451}
1452
1454// UNDER CONSTRUCTION: 5/19/09 MES
1455{
1456 /* Returns false iff we defer computing this spair. */
1457 /* If false is returned, this routine has grabbed the spair 'p'. */
1458 int tmf, wt;
1459 int count = -1;
1460
1462
1463 if (M2_gbTrace == 15)
1464 {
1465 buffer o;
1466 o << "considering ";
1467 spair_text_out(o, p);
1468 o << " : ";
1469 emit_line(o.str());
1470 }
1471 compute_s_pair(p); /* Changes the type, possibly */
1472
1473 while (!R->gbvector_is_zero(p->f()))
1474 {
1475 if (count++ > max_reduction_count)
1476 {
1478 return false;
1479 }
1480 if (M2_gbTrace >= 5)
1481 {
1482 if ((wt = weightInfo_->gbvector_weight(p->f(), tmf)) > this_degree)
1483 {
1484 buffer o;
1485 o << "ERROR: degree of polynomial is too high: deg " << wt
1486 << " termwt " << tmf << " expectedeg " << this_degree
1487 << newline;
1488 emit(o.str());
1489 }
1490 }
1491
1492 int gap, w;
1493 R->gbvector_get_lead_exponents(_F, p->f(), EXP);
1494 int x = p->f()->comp;
1495 mpz_srcptr c = p->f()->coeff.get_mpz();
1496
1497 w = find_good_term_divisor_ZZ(c, EXP, x, this_degree, gap);
1498
1499 // If w < 0, then no divisor was found. Is there a GB element of
1500 // the same degree as this one, and with the same exponent vector?
1501 // If so, use gcdextended to find (g,u,v),
1502 if (w < 0 || gap > 0)
1503 {
1505 lookupZZ->find_exact_monomial(EXP, x, first_in_degree);
1506 if (t != nullptr)
1507 {
1508 // f <-- u*p+v*f (same with syz versions), need to change lookupZZ
1509 // too?
1510 // p <-- c*p-d*f
1511 gbelem *g = gb[t->_val];
1512 if (M2_gbTrace >= 10)
1513 {
1514 buffer o;
1515 o << " swapping with GB element " << t->_val;
1516 emit_line(o.str());
1517 }
1518
1519 // If the element p is a generator, then we must assume that now
1520 // the
1521 // swapped g is a (possible) minimal generator.
1522 g->minlevel |= ELEM_MINGB;
1523 if (p->type == SPAIR::SPAIR_GEN || (g->minlevel & ELEM_MINGEN))
1524 {
1525 g->minlevel |= ELEM_MINGEN;
1526 p->type = SPAIR::SPAIR_GEN;
1527 }
1528
1529 R->gbvector_replace_2by2_ZZ(
1530 _F, _Fsyz, p->f(), p->fsyz(), g->g.f, g->g.fsyz);
1531 // Before continuing, do remainder of g->g
1533
1534 if (M2_gbTrace >= 10)
1535 {
1536 buffer o;
1537 o << " swap yielded";
1538 emit_line(o.str());
1539 o.reset();
1540 o << " ";
1541 R->gbvector_text_out(o, _F, p->f(), 3);
1542 emit_line(o.str());
1543 o.reset();
1544 o << " ";
1545 R->gbvector_text_out(o, _F, g->g.f, 3);
1546 emit_line(o.str());
1547 }
1548 continue;
1549 }
1550 }
1551
1552 if (w < 0) break;
1553 if (gap > 0)
1554 {
1555 POLY h;
1556 h.f = R->gbvector_copy(p->x.f.f);
1557 h.fsyz = R->gbvector_copy(p->x.f.fsyz);
1558 insert_gb(h, (p->type == SPAIR::SPAIR_GEN ? ELEM_MINGEN : 0));
1559 }
1560 POLY g = gb[w]->g;
1561
1562 R->gbvector_reduce_lead_term_ZZ(
1563 _F, _Fsyz, p->f(), p->fsyz(), g.f, g.fsyz);
1565 if (M2_gbTrace == 15)
1566 {
1567 buffer o;
1568 o << " reducing by g" << w;
1569 o << ", yielding ";
1570 R->gbvector_text_out(o, _F, p->f(), 3);
1571 emit_line(o.str());
1572 }
1573 if (R->gbvector_is_zero(p->f())) break;
1574 if (gap > 0)
1575 {
1576 p->deg += gap;
1577 if (M2_gbTrace == 15)
1578 {
1579 buffer o;
1580 o << " deferring to degree " << p->deg;
1581 emit_line(o.str());
1582 }
1584 return false;
1585 }
1586 }
1587 if (M2_gbTrace >= 4 && M2_gbTrace != 15)
1588 {
1589 buffer o;
1590 o << "." << count;
1591 emit_wrapped(o.str());
1592 }
1593 return true;
1594}
1595
1597{
1598 if (over_ZZ()) return reduce_ZZ(p);
1599 return reduce_kk(p);
1600}
1601
1602/***********************
1603 * gbasis routines *****
1604 ***********************/
1605
1607 exponents_t e,
1608 int x,
1609 int degf,
1610 int &result_gap)
1611{
1612 // Get all of the term divisors.
1613 // Choose one with the smallest gap.
1614 int i, gap, newgap, egap;
1615 int n = 0;
1616
1617 (void) c;
1619 egap = degf - weightInfo_->exponents_weight(e, x);
1620
1621 /* First search for ring divisors */
1622 if (ringtableZZ)
1623 n += ringtableZZ->find_monomial_divisors(-1, e, 1, &divisors);
1624
1625 /* Next search for GB divisors */
1626 n += lookupZZ->find_monomial_divisors(-1, e, x, &divisors);
1627
1628 /* Now find the minimal gap value */
1629 if (n == 0) return -1;
1630 int result = divisors[0]->_val;
1631 gbelem *tg = gb[result];
1632 gap = tg->gap - egap;
1633 if (gap <= 0)
1634 gap = 0;
1635 else
1636 for (i = 1; i < n; i++)
1637 {
1638 int new_val = divisors[i]->_val;
1639 tg = gb[new_val];
1640 newgap = tg->gap - egap;
1641 if (newgap <= 0)
1642 {
1643 gap = 0;
1644 result = new_val;
1645 break;
1646 }
1647 else if (newgap < gap)
1648 {
1649 result = new_val;
1650 gap = newgap;
1651 }
1652 }
1653 result_gap = gap;
1654 return result;
1655}
1656
1658 exponents_t e,
1659 int x,
1660 int degf,
1661 int &result_gap)
1662{
1663 // Get all of the term divisors.
1664 // Choose one with the smallest gap.
1665 int i, gap, newgap, egap;
1666 int n = 0;
1667
1669 egap = degf - weightInfo_->exponents_weight(e, x);
1670
1671 /* First search for ring divisors */
1672 if (ringtableZZ) n += ringtableZZ->find_term_divisors(-1, c, e, 1, &divisors);
1673
1674 /* Next search for GB divisors */
1675 n += lookupZZ->find_term_divisors(-1, c, e, x, &divisors);
1676
1677 /* Now find the minimal gap value */
1678 if (n == 0)
1679 {
1680 result_gap = 0;
1681 return -1;
1682 }
1683 int result = divisors[n - 1]->_val;
1684 gbelem *tg = gb[result];
1685 gap = tg->gap - egap;
1686 if (gap <= 0)
1687 gap = 0;
1688 else
1689 for (i = n - 2; i >= 0; i--)
1690 {
1691 int new_val = divisors[i]->_val;
1692 tg = gb[new_val];
1693 newgap = tg->gap - egap;
1694 if (newgap <= 0)
1695 {
1696 gap = 0;
1697 result = new_val;
1698 break;
1699 }
1700 else if (newgap < gap)
1701 {
1702 result = new_val;
1703 gap = newgap;
1704 }
1705 }
1706 result_gap = gap;
1707 return result;
1708}
1709
1710int gbA::find_good_divisor(exponents_t e, int x, int degf, int &result_gap)
1711// Returns an integer w.
1712// if w >=0: gb[w]'s lead term divides [e,x].
1713// if w<0: no gb[w] has lead term dividing [e,x].
1714{
1715 int n = 0;
1716 int gap;
1717 int egap = degf - weightInfo_->exponents_weight(e, x);
1718
1719 VECTOR(MonomialTable::mon_term *) divisors;
1720
1722 {
1723 gbelem *tg = gb[divisor_previous];
1724 gap = tg->gap - egap;
1725 if (gap <= 0 && exponents_divide(_nvars, tg->lead, e))
1726 {
1727 result_gap = 0;
1728 return divisor_previous;
1729 }
1730 }
1731
1732 /* First search for ring divisors */
1733 if (ringtable) n += ringtable->find_divisors(-1, e, 1, &divisors);
1734
1735 /* Next search for GB divisors */
1736 n += lookup->find_divisors(-1, e, x, &divisors);
1737
1738 if (M2_gbTrace == 15 && n >= 2)
1739 {
1740 gbelem *tg = gb[divisors[n - 1]->_val];
1741 int sz = tg->size;
1742 if (sz >= 0) // was 3, why??
1743 {
1744 buffer o;
1745 o << " reducers: ";
1746 for (int j = 0; j < n; j++) o << "g" << divisors[j]->_val << " ";
1747 emit_line(o.str());
1748 }
1749 }
1750 /* Now find the minimal gap value */
1751 if (n == 0)
1752 {
1753 result_gap = 0;
1754 return -1;
1755 }
1756
1757 if (is_local_gb)
1758 {
1759 // new version, under development
1760 int i = 0;
1761 int j = divisors[i]->_val;
1763 gap = gb[j]->gap - egap;
1764 if (gap < 0) gap = 0;
1765 while (true)
1766 {
1767 int mingap = gap;
1768 int best = j;
1769 do
1770 {
1771 if (++i == n)
1772 {
1773 divisor_previous = best;
1775 result_gap = mingap; // a difference between two gaps is no
1776 // longer a "gap"...
1777 if (result_gap < 0)
1778 result_gap = 0; // I'm not sure this is needed.
1779 return best;
1780 }
1781 j = divisors[i]->_val;
1782 gap = gb[j]->gap - egap;
1783 if (gap < 0) gap = 0;
1784 }
1785 while (gap >= mingap); // used to be: (! gap < mingap || gap ==
1786 // mingap && false)
1787 }
1788 }
1789 else
1790 {
1791 int newgap;
1792 int result = divisors[n - 1]->_val;
1793 gbelem *tg = gb[result];
1794 gap = tg->gap - egap;
1795 if (gap <= 0)
1796 {
1797 gap = 0;
1798 int minsz = tg->size;
1799 for (int i = n - 2; i >= 0; i--)
1800 {
1801 int new_val = divisors[i]->_val;
1802 tg = gb[new_val];
1803 int sz = tg->size;
1804 if (sz < minsz)
1805 {
1806 if (tg->gap <= egap)
1807 {
1808 minsz = sz;
1809 result = new_val;
1810 }
1811 }
1812 }
1813 }
1814 else
1815 // for (i=1; i<n; i++)
1816 for (int i = n - 2; i >= 0; i--)
1817 {
1818 int new_val = divisors[i]->_val;
1819 tg = gb[new_val];
1820
1821 newgap = tg->gap - egap;
1822 if (newgap <= 0)
1823 {
1824 gap = 0;
1825 result = new_val;
1826 break;
1827 }
1828 else if (newgap < gap)
1829 {
1830 result = new_val;
1831 gap = newgap;
1832 }
1833 }
1836 result_gap = gap;
1837 return result;
1838 }
1839}
1840
1841void gbA::remainder(POLY &f, int degf, bool use_denom, ring_elem &denom)
1842{
1843 if (over_ZZ())
1844 remainder_ZZ(f, degf, use_denom, denom);
1845 else
1846 remainder_non_ZZ(f, degf, use_denom, denom);
1847}
1848
1849void gbA::remainder_ZZ(POLY &f, int degf, bool use_denom, ring_elem &denom)
1850{
1851 gbvector head;
1852 gbvector *frem = &head;
1853
1855
1856 (void) use_denom;
1857 (void) denom;
1858 frem->next = nullptr;
1859 int count = 0;
1860 POLY h = f;
1861 while (!R->gbvector_is_zero(h.f))
1862 {
1863 int gap;
1864 R->gbvector_get_lead_exponents(_F, h.f, EXP);
1865 int x = h.f->comp;
1867 h.f->coeff.get_mpz(), EXP, x, degf, gap);
1868 if (w < 0 || gap > 0)
1869 {
1870 frem->next = h.f;
1871 frem = frem->next;
1872 h.f = h.f->next;
1873 frem->next = nullptr;
1874 }
1875 else
1876 {
1877 POLY g = gb[w]->g;
1878 if (!R->gbvector_reduce_lead_term_ZZ(
1879 _F, _Fsyz, h.f, h.fsyz, g.f, g.fsyz))
1880 {
1881 // This term is still there, so we must move it to result.
1882 frem->next = h.f;
1883 frem = frem->next;
1884 h.f = h.f->next;
1885 frem->next = nullptr;
1886 }
1887 count++;
1888 if (M2_gbTrace == 15)
1889 {
1890 buffer o;
1891 o << " tail rem by g" << w;
1892 o << ", yielding ";
1893 R->gbvector_text_out(o, _F, h.f, 3);
1894 emit_line(o.str());
1895 }
1896 }
1897 }
1898 h.f = head.next;
1899 // Negate these if needed
1900 if (h.f != nullptr && mpz_sgn(h.f->coeff.get_mpz()) < 0)
1901 {
1902 R->gbvector_mult_by_coeff_to(h.f, globalZZ->minus_one());
1903 R->gbvector_mult_by_coeff_to(h.fsyz, globalZZ->minus_one());
1904 }
1905 f.f = h.f;
1906 f.fsyz = h.fsyz;
1907 if ((M2_gbTrace & PRINT_SPAIR_TRACKING) != 0)
1908 {
1909 buffer o;
1910 o << "number of reduction steps was " << count;
1911 emit_line(o.str());
1912 }
1913 else if (M2_gbTrace >= 4 && M2_gbTrace != 15)
1914 {
1915 buffer o;
1916 o << "," << count;
1917 emit_wrapped(o.str());
1918 }
1919}
1920
1922{
1923 gbvector head;
1924 gbvector *frem = &head;
1925 int count = 0;
1926 POLY h = f;
1927
1929
1930 frem->next = h.f;
1931 frem = frem->next;
1932 h.f = h.f->next;
1933 frem->next = nullptr;
1934
1935 while (!R->gbvector_is_zero(h.f))
1936 {
1937 int gap;
1938 R->gbvector_get_lead_exponents(_F, h.f, EXP);
1939 int x = h.f->comp;
1941 h.f->coeff.get_mpz(), EXP, x, degf, gap);
1942 // replaced gap, g.
1943 if (w < 0 || gap > 0)
1944 {
1945 frem->next = h.f;
1946 frem = frem->next;
1947 h.f = h.f->next;
1948 frem->next = nullptr;
1949 }
1950 else
1951 {
1952 POLY g = gb[w]->g;
1953 if (!R->gbvector_reduce_lead_term_ZZ(
1954 _F, _Fsyz, h.f, h.fsyz, g.f, g.fsyz))
1955 {
1956 // This term is still there, so we must move it to result.
1957 frem->next = h.f;
1958 frem = frem->next;
1959 h.f = h.f->next;
1960 frem->next = nullptr;
1961 }
1962 count++;
1963 // stats_ntail++;
1964 if (M2_gbTrace == 15)
1965 {
1966 buffer o;
1967 o << " tail red by g" << w;
1968 o << ", yielding ";
1969 R->gbvector_text_out(o, _F, h.f, 3);
1970 emit_line(o.str());
1971 }
1972 }
1973 }
1974 h.f = head.next;
1975 // Negate these if needed
1976 if (h.f != nullptr && mpz_sgn(h.f->coeff.get_mpz()) < 0)
1977 {
1978 R->gbvector_mult_by_coeff_to(h.f, globalZZ->minus_one());
1979 R->gbvector_mult_by_coeff_to(h.fsyz, globalZZ->minus_one());
1980 }
1981 f.f = h.f;
1982 f.fsyz = h.fsyz;
1983 if ((M2_gbTrace & PRINT_SPAIR_TRACKING) != 0)
1984 {
1985 buffer o;
1986 o << "number of reduction steps was " << count;
1987 emit_line(o.str());
1988 }
1989 else if (M2_gbTrace >= 4 && M2_gbTrace != 15)
1990 {
1991 buffer o;
1992 o << "," << count;
1993 emit_wrapped(o.str());
1994 }
1995}
1996
1997void gbA::remainder_non_ZZ(POLY &f, int degf, bool use_denom, ring_elem &denom)
1998// find the remainder of f = [g,gsyz] wrt the GB,
1999// i.e. replace f with h[h,hsyz], st
2000// base not ZZ:
2001// h = f - sum(a_i * g_i), in(f) not in in(G)
2002// hsyz = fsyz - sum(a_i * gsyz_i)
2003// denom is unchanged
2004// base is ZZ:
2005// h = c*f - sum(a_i * g_i), in(f) not in in(G),
2006// hsyz = c*fsyz - sum(a_i * gsyz_i)
2007// but a_i,h are all polynomials with ZZ coefficients (not QQ).
2008// denom *= c
2009// (Here: G = (g_i) is the GB, and a_i are polynomials generated
2010// during division).
2011// c is an integer, and is returned as 'denom'.
2012// Five issues:
2013// (a) if gcd(c, coeffs(f)) becomes > 1, can we divide
2014// c, f, by this gcd? If so, how often do we do this?
2015// (b) do we reduce by any element of the GB, or only those whose
2016// sugar degree is no greater than degf?
2017// (c) can we exclude an element of the GB from the g_i?
2018// (for use in auto reduction).
2019// (d) can we reduce by the minimal GB instead of the original GB?
2020// ANSWER: NO. Instead, use a routine to make a new GB.
2021// (e) Special handling of quotient rings: none needed.
2022{
2024
2025 gbvector head;
2026 gbvector *frem = &head;
2027
2028 frem->next = nullptr;
2029 int count = 0;
2030 POLY h = f;
2031 while (!R->gbvector_is_zero(h.f))
2032 {
2033 int gap;
2034 R->gbvector_get_lead_exponents(_F, h.f, EXP);
2035 int x = h.f->comp;
2036 int w = find_good_divisor(EXP, x, degf, gap);
2037 // replaced gap, g.
2038 if (w < 0 || gap > 0)
2039 {
2040 frem->next = h.f;
2041 frem = frem->next;
2042 h.f = h.f->next;
2043 frem->next = nullptr;
2044 }
2045 else
2046 {
2047 POLY g = gb[w]->g;
2048 R->gbvector_reduce_lead_term(
2049 _F, _Fsyz, head.next, h.f, h.fsyz, g.f, g.fsyz, use_denom, denom);
2050 count++;
2051 // stats_ntail++;
2052 if (M2_gbTrace >= 10)
2053 {
2054 buffer o;
2055 o << " tail reducing by ";
2056 R->gbvector_text_out(o, _F, g.f, 2);
2057 o << "\n giving ";
2058 R->gbvector_text_out(o, _F, h.f, 3);
2059 emit_line(o.str());
2060 }
2061 }
2062 }
2063 h.f = head.next;
2064 R->gbvector_remove_content(h.f, h.fsyz, use_denom, denom);
2065 f.f = h.f;
2066 f.fsyz = h.fsyz;
2067 if ((M2_gbTrace & PRINT_SPAIR_TRACKING) != 0)
2068 {
2069 buffer o;
2070 o << "number of reduction steps was " << count;
2071 emit_line(o.str());
2072 }
2073 else if (M2_gbTrace >= 4 && M2_gbTrace != 15)
2074 {
2075 buffer o;
2076 o << "," << count;
2077 emit_wrapped(o.str());
2078 }
2079}
2080
2081/********************
2082 ** State machine ***
2083 ********************/
2084
2085// ZZZZ split
2087{
2088 /* Loop backwards while degree doesn't change */
2089 /* Don't change quotient ring elements */
2090 gbelem *me = gb[id];
2091 int a = me->gap; // Only auto reduce those that are of the same degree
2092 // and not a higher gap level
2093 for (int i = INTSIZE(gb) - 1; i >= first_gb_element; i--)
2094 {
2095 if (!gb[i]) continue;
2096 if (i == id) continue;
2097 gbelem *g = gb[i];
2098 if (g->deg < me->deg) return;
2099 if (g->gap < a) continue;
2100 if (M2_gbTrace >= 10)
2101 {
2102 buffer o;
2103 o << " auto reduce " << i << " by " << id;
2104 emit_line(o.str());
2105 }
2106 if (over_ZZ())
2107 {
2108 R->gbvector_auto_reduce_ZZ(_F,
2109 _Fsyz,
2110 g->g.f,
2111 g->g.fsyz, // these are modified
2112 me->g.f,
2113 me->g.fsyz);
2114 }
2115 else
2116 {
2117 R->gbvector_auto_reduce(_F,
2118 _Fsyz,
2119 g->g.f,
2120 g->g.fsyz, // these are modified
2121 me->g.f,
2122 me->g.fsyz);
2123 }
2124 }
2125}
2126
2128{
2129 _syz.push_back(f);
2130 n_syz++;
2131
2132 if (M2_gbTrace >= 10)
2133 {
2134 buffer o;
2135 o << " new syzygy : ";
2136 R->gbvector_text_out(o, _Fsyz, f, 3);
2137 emit_line(o.str());
2138 }
2139}
2140
2142{
2143 /* Reduce this element as far as possible. This either removes content,
2144 makes it monic, or at least negates it so the lead coeff is positive. */
2145 ring_elem junk;
2146
2147 // DEBUG BLOCK int fwt;
2148 // int fdeg = weightInfo_->gbvector_weight(f.f, fwt);
2149 // fprintf(stderr, "inserting GB element %d, thisdeg %d deg %d gap %d\n",
2150 // gb.size(),
2151 // this_degree,
2152 // fdeg,
2153 // fdeg-fwt);
2154
2155 if (is_local_gb)
2156 R->gbvector_remove_content(f.f, f.fsyz, false, junk);
2157 else
2158 remainder(f, this_degree, false, junk);
2159
2160 // fdeg = weightInfo_->gbvector_weight(f.f, fwt);
2161 // fprintf(stderr, " after remainder deg %d gap %d\n",
2162 // fdeg,
2163 // fdeg-fwt);
2164
2165 stats_ngb++;
2166
2167 // Complete hack for getting bug fix to get test/isSubset.m2 to work again for
2168 // 1.3:
2169 // over ZZ, always make gb elements non reducers...
2170 if (over_ZZ()) minlevel |= ELEM_MINGB;
2171
2172 gbelem *g = gbelem_make(f.f, f.fsyz, minlevel, this_degree);
2173 minimal_gb_valid = false;
2174 int me = INTSIZE(gb);
2175 gb.push_back(g);
2176 forwardingZZ.push_back(-1);
2177 n_gb++;
2178 int x = g->g.f->comp;
2179
2180 // In a encoded Schreyer order, the following line might miss subring
2181 // elements.
2182 // But it at least won't be incorrect...
2183 if (R->get_flattened_monoid()->in_subring(1, g->g.f->monom)) n_subring++;
2184
2185 if (over_ZZ())
2186 lookupZZ->insert(g->g.f->coeff.get_mpz(), g->lead, x, me);
2187 else
2188 lookup->insert(g->lead, x, me);
2189
2190 if (M2_gbTrace == 15)
2191 {
2192 buffer o;
2193 o << " new ";
2194 gbelem_text_out(o, INTSIZE(gb) - 1);
2195 emit_line(o.str());
2196 }
2197 else if (M2_gbTrace >= 5)
2198 {
2199 const int N = 100;
2200 char s[N];
2201 buffer o;
2202 snprintf(s, N, "new-inserting element %d (minimal %d): ", me, minlevel);
2203 o << s;
2204 R->gbvector_text_out(o, _F, g->g.f);
2205 emit_line(o.str());
2206 o.reset();
2207 o << " syzygy : ";
2208 R->gbvector_text_out(o, _Fsyz, g->g.fsyz);
2209 emit_line(o.str());
2210 }
2211
2212 if (!is_local_gb) auto_reduce_by(me);
2213
2214 if (use_hilb)
2215 {
2216 hilb_new_elems = true;
2217 if (--hilb_n_in_degree == 0) flush_pairs();
2218 }
2219 else
2220 {
2221#ifdef DEVELOPMENT
2222#warning "todo: codimension stop condition"
2223#endif
2224 // codim test is set. Compute the codimension now.
2225 }
2226
2227 if (M2_gbTrace >= 10)
2228 {
2229 // lookupZZ->showmontable();
2230 // show();
2231 }
2232}
2233
2235{
2236 /* Reduce this element as far as possible. This either removes content,
2237 makes it monic, or at least negates it so the lead coeff is positive. */
2238 ring_elem not_used;
2239
2240 stats_ngb++;
2241 n_gb++;
2242
2243 int gbval = t->_val;
2244 gbelem *g = gb[gbval];
2245 gb[gbval] = nullptr;
2246
2247 g->deg = this_degree; // replace the degree
2248 g->minlevel |= ELEM_MINGB;
2249 minimal_gb_valid = false;
2250 int me = INTSIZE(gb);
2251
2252 if (is_local_gb)
2253 R->gbvector_remove_content(g->g.f, g->g.fsyz, false, not_used);
2254 else
2256
2257 // tail_remainder_ZZ(g->g,this_degree);
2258 gb.push_back(g);
2259 forwardingZZ.push_back(-1);
2260 forwardingZZ[gbval] = INTSIZE(gb) - 1;
2261
2262 lookupZZ->change_coefficient(t, g->g.f->coeff.get_mpz(), me);
2263 if (M2_gbTrace == 15)
2264 {
2265 buffer o;
2266 o << " retiring g" << gbval << " with new ";
2267 // o << " new ";
2268 gbelem_text_out(o, INTSIZE(gb) - 1);
2269
2270 emit_line(o.str());
2271 }
2272 else if (M2_gbTrace >= 5)
2273 {
2274 const int N = 100;
2275 char s[N];
2276 buffer o;
2277 snprintf(s, N,
2278 "replacing-inserting element %d (minimal %d replacing %d): ",
2279 me,
2280 g->minlevel,
2281 gbval);
2282 o << s;
2283 R->gbvector_text_out(o, _F, g->g.f);
2284 emit_line(o.str());
2285 o.reset();
2286 o << " syzygy : ";
2287 R->gbvector_text_out(o, _Fsyz, g->g.fsyz);
2288 emit_line(o.str());
2289 }
2290
2291 if (!is_local_gb) auto_reduce_by(me);
2292}
2293
2295{
2296 if (p->type == SPAIR::SPAIR_GCD_ZZ or p->type == SPAIR::SPAIR_SPAIR)
2297 {
2298 return gb[p->x.pair.i] == nullptr or gb[p->x.pair.j] == nullptr;
2299 }
2300 if (p->type == SPAIR::SPAIR_RING)
2301 {
2302 return gb[p->x.pair.i] == nullptr;
2303 }
2304 if (p->type == SPAIR::SPAIR_SKEW)
2305 {
2306 return gb[p->x.pair.i] == nullptr;
2307 }
2308 return false;
2309}
2310
2312{
2313 stats_npairs++;
2314 if (false and spair_is_retired(p))
2315 {
2317 spair_delete(p);
2318 return true;
2319 }
2320
2321 bool not_deferred = reduceit(p);
2322 if (!not_deferred) return true;
2323
2324 gbelem_type minlevel =
2325 (p->type == SPAIR::SPAIR_GEN ? ELEM_MINGEN : 0) | ELEM_MINGB;
2326
2327 POLY f = p->x.f;
2328 p->x.f.f = nullptr;
2329 p->x.f.fsyz = nullptr;
2330 spair_delete(p);
2331
2332 if (!R->gbvector_is_zero(f.f))
2333 {
2334 insert_gb(f, minlevel);
2335 if (M2_gbTrace == 3) emit_wrapped("m");
2336 }
2337 else
2338 {
2339 originalR->get_quotient_info()->gbvector_normal_form(_Fsyz, f.fsyz);
2340 if (!R->gbvector_is_zero(f.fsyz))
2341 {
2342 /* This is a syzygy */
2344 if (M2_gbTrace == 3) emit_wrapped("z");
2345 }
2346 else
2347 {
2348 if (M2_gbTrace == 3) emit_wrapped("o");
2349 }
2350 }
2351 return true;
2352}
2353
2355{
2356 // This handles everything but stop_.always, stop_.degree_limit
2357 if (stop_.basis_element_limit > 0 && gb.size() >= stop_.basis_element_limit)
2358 return COMP_DONE_GB_LIMIT;
2359 if (stop_.syzygy_limit > 0 && n_syz >= stop_.syzygy_limit)
2360 return COMP_DONE_SYZ_LIMIT;
2361 if (stop_.pair_limit > 0 && n_pairs_computed >= stop_.pair_limit)
2362 return COMP_DONE_PAIR_LIMIT;
2363 if (stop_.just_min_gens && n_gens_left == 0) return COMP_DONE_MIN_GENS;
2364 if (stop_.subring_limit > 0 && n_subring >= stop_.subring_limit)
2366 if (stop_.use_codim_limit)
2367 {
2368 // Compute the codimension
2369 int c = 0;
2370 // int c = codim_of_lead_terms();
2371 if (c >= stop_.codim_limit) return COMP_DONE_CODIM;
2372 }
2373 return COMP_COMPUTING;
2374}
2375
2377{
2379 for (int i = first_gb_element; i < gb.size(); i++)
2380 {
2381 gbelem *g = gb[i];
2382 if (g->minlevel & ELEM_MINGB)
2383 {
2384 gbvector *f = g->g.f;
2385 assert(f != 0);
2386 // Only grab the lead term, which should be non-null
2387 gbvector *fnext = f->next;
2388 f->next = nullptr;
2389 vec v = originalR->translate_gbvector_to_vec(_F, f);
2390 f->next = fnext;
2391 result.append(v);
2392 }
2393 }
2394 return result.to_matrix();
2395}
2396
2397// new code
2399{
2401 spair *p;
2402
2403 // initial state is STATE_NEWDEGREE
2404
2405 if (stop_.always_stop) return; // don't change status
2406
2407 if ((ret = computation_is_complete()) != COMP_COMPUTING)
2408 {
2409 set_status(ret);
2410 return;
2411 }
2412
2413 if (M2_gbTrace == 15)
2414 {
2415 emit_line("[gb]");
2416 }
2417 else if (M2_gbTrace >= 1)
2418 {
2419 emit_wrapped("[gb]");
2420 }
2421 for (;;)
2422 {
2423 if (stop_.stop_after_degree && this_degree > stop_.degree_limit->array[0])
2424 {
2425 // Break out now if we don't have anything else to compute in this
2426 // degree.
2428 return;
2429 }
2431 {
2432 }
2433
2434 switch (state)
2435 {
2436 case STATE_NEWPAIRS:
2437 // Loop through all of the new GB elements, and
2438 // compute spairs. Start at np_i
2439 // np_i is initialized at the beginning, and also here.
2440 while (np_i < n_gb)
2441 {
2442 if (system_interrupted())
2443 {
2445 return;
2446 }
2447 if (gb[np_i])
2448 {
2449 if (gb[np_i]->minlevel & ELEM_MINGB) update_pairs(np_i);
2450 }
2451 np_i++;
2452 }
2453 state = STATE_HILB;
2454 [[fallthrough]];
2455
2456 case STATE_HILB:
2457 // If we are using hilbert function tracking:
2458 // Recompute the Hilbert function if new GB elements have been added
2459
2460 if (hilb_new_elems)
2461 {
2462 // Recompute h, hf_diff
2465 if (h == nullptr)
2466 {
2468 return;
2469 }
2470 hf_diff = (*h) - (*hf_orig);
2471 hilb_new_elems = false;
2472 }
2474 [[fallthrough]];
2475
2476 case STATE_NEWDEGREE:
2477 // Get the spairs and generators for the next degree
2478
2479 if (S->n_in_degree == 0)
2480 {
2481 // int old_degree = this_degree;
2483 this_degree); // sets this_degree
2484 // if (old_degree < this_degree)
2485 // first_in_degree = INTSIZE(gb);
2487 if (npairs == 0)
2488 {
2489 state = STATE_DONE;
2491 return;
2492 }
2493 if (stop_.stop_after_degree &&
2494 this_degree > stop_.degree_limit->array[0])
2495 {
2497 return;
2498 }
2499 if (use_hilb)
2500 {
2503 if (error())
2504 {
2505 // The previous line can give an error, which means that
2506 // the Hilbert
2507 // function declared was actually incorrect.
2509 return;
2510 }
2511 if (hilb_n_in_degree == 0) flush_pairs();
2512 }
2513 }
2514 if (M2_gbTrace == 15)
2515 {
2516 buffer o;
2517 o << "DEGREE " << this_degree;
2518 o << ", number of spairs = " << npairs;
2519 if (use_hilb)
2520 o << ", expected number in this degree = "
2522 emit_line(o.str());
2523 }
2524 else if (M2_gbTrace >= 1)
2525 {
2526 buffer o;
2527 o << '{' << this_degree << '}';
2528 o << '(';
2529 if (use_hilb) o << hilb_n_in_degree << ',';
2530 o << npairs << ')';
2531 emit_wrapped(o.str());
2532 }
2533 ar_i = n_gb;
2534 ar_j = ar_i + 1;
2536
2537 case STATE_SPAIRS:
2538 case STATE_GENS:
2539 // Compute the spairs for this degree
2540 while ((p = spair_set_next()) != nullptr)
2541 {
2543 npairs--;
2545
2546 if ((ret = computation_is_complete()) != COMP_COMPUTING)
2547 {
2548 set_status(ret);
2549 return;
2550 }
2551
2552 if (system_interrupted())
2553 {
2555 return;
2556 }
2557 }
2559 [[fallthrough]];
2560 // or state = STATE_NEWPAIRS
2561
2562 case STATE_AUTOREDUCE:
2563 // This is still possibly best performed when inserting a new
2564 // element
2565 // Perform the necessary or desired auto-reductions
2566 if (!is_local_gb)
2567 while (ar_i < n_gb)
2568 {
2569 if (gb[ar_i])
2570 while (ar_j < n_gb)
2571 {
2572 if (system_interrupted())
2573 {
2575 return;
2576 }
2577 if (gb[ar_j])
2578 {
2579 if (over_ZZ())
2580 {
2581 R->gbvector_auto_reduce_ZZ(_F,
2582 _Fsyz,
2583 gb[ar_i]->g.f,
2584 gb[ar_i]->g.fsyz,
2585 gb[ar_j]->g.f,
2586 gb[ar_j]->g.fsyz);
2587 }
2588 else
2589 {
2590 R->gbvector_auto_reduce(_F,
2591 _Fsyz,
2592 gb[ar_i]->g.f,
2593 gb[ar_i]->g.fsyz,
2594 gb[ar_j]->g.f,
2595 gb[ar_j]->g.fsyz);
2596 }
2597 }
2598 ar_j++;
2599 }
2600 ar_i++;
2601 ar_j = ar_i + 1;
2602 }
2604 break;
2605
2606 case STATE_DONE:
2607 return;
2608 }
2609 }
2610}
2611
2613{
2614 ncalls = 0;
2615 nloops = 0;
2616 nsaved_unneeded = 0;
2618 if (M2_gbTrace >= 1)
2619 {
2621 if (M2_gbTrace >= 3)
2622 {
2623 buffer o;
2624 emit_line(o.str());
2625 o.reset();
2626 o << "#reduction steps = " << stats_nreductions;
2627 emit_line(o.str());
2628 o.reset();
2629 o << "#spairs done = " << stats_npairs;
2630 emit_line(o.str());
2631 o.reset();
2632 o << "ncalls = " << ncalls;
2633 emit_line(o.str());
2634 o.reset();
2635 o << "nloop = " << nloops;
2636 emit_line(o.str());
2637 o.reset();
2638 o << "nsaved = " << nsaved_unneeded;
2639 emit_line(o.str());
2640 }
2641 if (M2_gbTrace >= 15) show();
2642 }
2643}
2644
2645/*******************************
2646 ** Minimalization of the GB ***
2647 *******************************/
2649{
2650 if (minimal_gb_valid) return;
2651
2652 delete minimal_gb;
2654
2655 VECTOR(POLY) polys;
2656 for (int i = first_gb_element; i < gb.size(); i++)
2657 if (gb[i])
2658 {
2659 if (gb[i]->minlevel & ELEM_MINGB) polys.push_back(gb[i]->g);
2660 }
2661
2662 minimal_gb->minimalize(polys);
2663 minimal_gb_valid = true;
2664}
2665
2666/*******************************
2667 ** Hilbert function routines **
2668 *******************************/
2669
2671{
2672 spair *p;
2673 while ((p = spair_set_next()) != nullptr)
2674 {
2675 n_saved_hilb++;
2676 spair_delete(p);
2677 }
2678}
2679
2680/*************************
2681 ** Top level interface **
2682 *************************/
2683
2685{
2686 // TODO Problems here:
2687 // -- check that the ring is correct
2688 // -- if the computation has already been started, this will fail
2689 // So probably an error should be given, and 0 returned in this case.
2690
2691 // We may only use the Hilbert function if syzygies are not being collected
2692 // since otherwise we will miss syzygies
2693
2694 if (over_ZZ())
2695 {
2696 ERROR(
2697 "cannot use Hilbert function for Groebner basis computation over the "
2698 "integers");
2699 return nullptr;
2700 }
2701 if (!_collect_syz)
2702 {
2703 hf_orig = hf;
2705 use_hilb = true;
2706 hilb_new_elems = true;
2707 state = STATE_HILB;
2708 }
2709
2710 return this;
2711}
2712
2713const Matrix /* or null */ *gbA::get_gb()
2714{
2715 minimalize_gb();
2716 // fprintf(stderr, "-- done with GB -- \n");
2717 return minimal_gb->get_gb();
2718}
2719
2720const Matrix /* or null */ *gbA::get_mingens()
2721{
2722 if (over_ZZ()) return get_gb();
2723 MatrixConstructor mat(_F, 0);
2724 for (VECTOR(gbelem *)::iterator i = gb.begin(); i != gb.end(); i++)
2725 if ((*i) and ((*i)->minlevel & ELEM_MINGEN))
2726 mat.append(originalR->translate_gbvector_to_vec(_F, (*i)->g.f));
2727 return mat.to_matrix();
2728}
2729
2730const Matrix /* or null */ *gbA::get_change()
2731{
2732 minimalize_gb();
2733 return minimal_gb->get_change();
2734}
2735
2736const Matrix /* or null */ *gbA::get_syzygies()
2737{
2738 // The (non-minimal) syzygy matrix
2739 MatrixConstructor mat(_Fsyz, 0);
2740 for (VECTOR(gbvector *)::iterator i = _syz.begin(); i != _syz.end(); i++)
2741 if (*i)
2742 {
2743 mat.append(originalR->translate_gbvector_to_vec(_Fsyz, *i));
2744 }
2745 return mat.to_matrix();
2746}
2747
2748const Matrix /* or null */ *gbA::get_initial(int nparts)
2749{
2750 minimalize_gb();
2751 return minimal_gb->get_initial(nparts);
2752}
2753
2755{
2756 minimalize_gb();
2757 return minimal_gb->get_parallel_lead_terms(w);
2758}
2759
2760const Matrix /* or null */ *gbA::matrix_remainder(const Matrix *m)
2761{
2762 minimalize_gb();
2763 return minimal_gb->matrix_remainder(m);
2764}
2765
2767 const Matrix /* or null */ **result_remainder,
2768 const Matrix /* or null */ **result_quotient)
2769{
2770 minimalize_gb();
2771 return minimal_gb->matrix_lift(m, result_remainder, result_quotient);
2772}
2773
2775// Return -1 if every column of 'm' reduces to zero.
2776// Otherwise return the index of the first column that
2777// does not reduce to zero.
2778{
2779 minimalize_gb();
2780 return minimal_gb->contains(m);
2781}
2782
2784// The computation is complete up through this degree.
2785{
2787}
2788
2789void gbA::text_out(buffer &o) const
2790/* This displays statistical information, and depends on the
2791 M2_gbTrace value */
2792{
2793 o << "# pairs computed = " << n_pairs_computed << newline;
2794 if (M2_gbTrace >= 5 && M2_gbTrace % 2 == 1)
2795 for (unsigned int i = 0; i < gb.size(); i++)
2796 if (gb[i])
2797 {
2798 o << i << '\t';
2799 R->gbvector_text_out(o, _F, gb[i]->g.f);
2800 o << newline;
2801 }
2802}
2803
2805{
2806 buffer o;
2807 spair_text_out(o, p);
2808 emit_line(o.str());
2809}
2810
2811void gbA::debug_spairs(spair *spairlist)
2812{
2813 spair *p = spairlist;
2814 while (p != nullptr)
2815 {
2816 debug_spair(p);
2817 p = p->next;
2818 }
2819}
2820
2821void gbA::debug_spair_array(spairs &spairlist)
2822{
2823 for (int i = 0; i < spairlist.size(); i++) debug_spair(spairlist[i]);
2824}
2825
2826void gbA::show() const
2827{
2828 buffer o;
2829 o << "Groebner basis, " << gb.size() << " elements";
2830 emit_line(o.str());
2831 o.reset();
2832 for (unsigned int i = 0; i < gb.size(); i++)
2833 {
2834 gbelem_text_out(o, i);
2835 emit_line(o.str());
2836 o.reset();
2837 }
2838}
2839
2841{
2842 buffer o;
2843
2844 long nmonoms = 0;
2845 for (int i = 0; i < gb.size(); i++)
2846 if (gb[i])
2847 {
2848 nmonoms += R->gbvector_n_terms(gb[i]->g.f);
2849 nmonoms += R->gbvector_n_terms(gb[i]->g.fsyz);
2850 }
2851 emit_line(o.str());
2852 o << "number of (nonminimal) gb elements = " << gb.size();
2853 emit_line(o.str());
2854 o.reset();
2855 o << "number of monomials = " << nmonoms;
2856 emit_line(o.str());
2857}
2858
2859// Local Variables:
2860// compile-command: "make -C $M2BUILDDIR/Macaulay2/e"
2861// indent-tabs-mode: nil
2862// End:
exponents::Exponents exponents_t
enum ComputationStatusCode set_status(enum ComputationStatusCode)
Definition comp.cpp:66
StopConditions stop_
Definition comp.hpp:75
Computation()
Definition comp.cpp:40
FreeModule * sub_space(int n) const
Definition freemod.cpp:197
Engine-side free module R^n over a Ring.
Definition freemod.hpp:66
Polynomial-ring view tuned for the inner loop of classical Buchberger Groebner-basis computations.
Definition gbring.hpp:120
Heuristic-weight evaluator for gbvectors, used during Groebner basis computation to drive the S-pair ...
Definition gbweight.hpp:67
const Ring * get_ring() const
Definition matrix.hpp:134
int n_cols() const
Definition matrix.hpp:147
const FreeModule * rows() const
Definition matrix.hpp:144
const FreeModule * cols() const
Definition matrix.hpp:145
Matrix * to_matrix()
void append(vec v)
Mutable builder used to assemble an immutable Matrix one column (or one term) at a time.
int numNonTermOrderVariables() const
Definition monoid.hpp:190
int numInvertibleVariables() const
Definition monoid.hpp:189
void insert(exponents_t exp, int comp, int id)
Definition montable.cpp:218
static MonomialTable * make(int nvars)
Definition montable.cpp:61
int find_divisors(int max, exponents_t exp, int comp, VECTOR(mon_term *) *result=nullptr)
Definition montable.cpp:152
Indexed table of monomials with fast "find a divisor" lookup, keyed by a free integer val per entry.
Definition montable.hpp:81
static MonomialTableZZ * make(int nvars)
static void find_weak_generators(int nvars, const VECTOR(mpz_srcptr) &coeffs, const VECTOR(exponents_t) &exps, const VECTOR(int) &comps, VECTOR(int) &result_positions, bool use_stable_sort=true)
virtual int n_fraction_vars() const
Definition polyring.hpp:295
virtual GBRing * get_gb_ring() const
Definition polyring.hpp:276
virtual const Monoid * getMonoid() const
Definition polyring.hpp:282
CoefficientType coefficient_type() const
Definition polyring.hpp:191
Abstract base for the engine's polynomial-ring hierarchy.
Definition polyring.hpp:96
static ReducedGB * create(const PolynomialRing *originalR0, const FreeModule *F0, const FreeModule *Fsyz0, const GBWeight *wt0=nullptr)
Definition reducedgb.cpp:11
virtual const PolynomialRing * cast_to_PolynomialRing() const
Definition ring.hpp:243
@ COEFF_ZZ
Definition ring.hpp:222
static RingElement * make_raw(const Ring *R, ring_elem f)
Definition relem.cpp:20
const Ring * get_ring() const
Definition relem.hpp:81
Front-end-visible "ring element" value: an engine ring_elem paired with the Ring* that gives it meani...
Definition relem.hpp:67
const FreeModule * F
gbA::spair * value
bool operator()(value a, value b)
int compare(value a, value b)
SPolySorter(GBRing *R0, const FreeModule *F0)
Comparator on gbA::spair* used by the default Groebner basis driver to order its S-pair queue.
char * str()
Definition buffer.hpp:72
void reset()
Definition buffer.hpp:69
enum ComputationStatusCode computation_is_complete()
void spairs_reverse(spair *&ps)
void spair_delete(spair *&p)
void compute_s_pair(spair *p)
void minimalize_pairs_non_ZZ(spairs &new_set)
int n_gens_left
MonomialTable * ringtable
int n_pairs_computed
int get_resolved_gb_index(int i) const
int spair_COMPONENT(spair *s)
virtual const Matrix * get_change()
void spair_text_out(buffer &o, spair *p)
MonomialTable * lookup
GBRing * R
int first_gb_element
void flush_pairs()
int stats_ngb
Ring::CoefficientType _coeff_type
const PolynomialRing * originalR
stash * gbelem_stash
void minimalize_gb()
virtual const Matrix * get_mingens()
int n_subring
void spair_set_show_mem_usage()
int find_good_monomial_divisor_ZZ(mpz_srcptr c, exponents_t e, int x, int degf, int &result_gap)
int _strategy
void tail_remainder_ZZ(POLY &f, int degf)
int _nvars
bool reduceit(spair *p)
void spair_set_lead_spoly(spair *p)
int divisor_previous_comp
spair * spair_node()
virtual M2_bool matrix_lift(const Matrix *m, const Matrix **result_remainder, const Matrix **result_quotient)
void replace_gb_element_ZZ(MonomialTableZZ::mon_term *t)
void spair_set_insert(spair *p)
void remainder_ZZ(POLY &f, int degf, bool use_denom, ring_elem &denom)
gbelem * gbelem_ring_make(gbvector *f)
long max_reduction_count
int gbelem_COMPONENT(gbelem *g)
virtual void text_out(buffer &o) const
gbelem * gbelem_make(gbvector *f, gbvector *fsyz, gbelem_type minlevel, int deg)
spair * spair_make_gcd_ZZ(int i, int j)
int ar_j
virtual const Matrix * matrix_remainder(const Matrix *m)
virtual int complete_thru_degree() const
int stats_nretired
MonomialTableZZ * lookupZZ
void remainder(POLY &f, int degf, bool use_denom, ring_elem &denom)
enum gbA::gbA_state state
ReducedGB * minimal_gb
spair * new_gen(int i, gbvector *f, ring_elem denom)
void show_mem_usage()
void show() const
int n_fraction_vars
void initialize(const Matrix *m, int csyz, int nsyz, M2_arrayint gb_weights, int strat, int max_reduction_count0)
bool use_hilb
@ STATE_DONE
@ STATE_NEWDEGREE
@ STATE_NEWPAIRS
@ STATE_HILB
@ STATE_SPAIRS
@ STATE_GENS
@ STATE_AUTOREDUCE
static gbA * create(const Matrix *m, M2_bool collect_syz, int n_rows_to_keep, M2_arrayint gb_weights, int strategy, M2_bool use_max_degree, int max_degree, int max_reduction_count)
void debug_spair_array(spairs &spairlist)
int n_gb
bool spair_is_retired(spair *p) const
int complete_thru_this_degree
void gbelem_text_out(buffer &o, int i, int nterms=3) const
spair * spair_make_gen(POLY f)
int stats_nreductions
int np_i
void auto_reduce_by(int id)
bool is_gcd_one_pair(spair *p)
virtual const Matrix * get_gb()
int hilb_n_in_degree
virtual const Matrix * get_initial(int nparts)
int ar_i
int stats_npairs
int find_good_divisor(exponents_t e, int x, int degf, int &result_gap)
M2_arrayint gb_weights
int n_saved_hilb
const GBWeight * weightInfo_
const FreeModule * _F
const FreeModule * _Fsyz
void start_computation()
void spairs_sort(int len, spair *&list)
stash * lcm_stash
bool _collect_syz
bool hilb_new_elems
int n_syz
bool reduce_ZZ(spair *p)
bool over_ZZ() const
int stats_ntail
void do_computation()
spair * spair_make_ring(int i, int j)
bool pair_not_needed(spair *p, gbelem *m)
int npairs
RingElement * hf_diff
virtual int contains(const Matrix *m)
int this_degree
stash * spair_stash
int spair_set_prepare_next_degree(int &nextdegree)
SPairSet * S
void minimalize_pairs(spairs &new_set)
bool is_local_gb
virtual const Matrix * get_syzygies()
void minimalize_pairs_ZZ(spairs &new_set)
bool process_spair(spair *p)
void remove_unneeded_pairs(int id)
Matrix * make_lead_term_matrix()
spair * spair_make_skew(int i, int v)
void debug_spair(spair *p)
spairs::iterator choose_pair(spairs::iterator first, spairs::iterator next)
virtual const Matrix * get_parallel_lead_terms(M2_arrayint w)
spair * spair_make(int i, int j)
void remainder_non_ZZ(POLY &f, int degf, bool use_denom, ring_elem &denom)
spair * spair_set_next()
int n_rows_per_syz
bool reduce_kk(spair *p)
int divisor_previous
bool minimal_gb_valid
void insert_gb(POLY f, gbelem_type minlevel)
void remove_spair_list(spair *&set)
void update_pairs(int id)
void debug_spairs(spair *spairlist)
virtual ~gbA()
virtual Computation * set_hilbert_function(const RingElement *h)
bool _is_ideal
const MonomialTableZZ * ringtableZZ
@ SPAIR_SPAIR
@ SPAIR_GCD_ZZ
@ SPAIR_RING
@ SPAIR_GEN
@ SPAIR_SKEW
@ SPAIR_ELEM
void remove_SPairSet()
exponents_t exponents_make()
void spair_set_defer(spair *&p)
gbelem * gbelem_copy(gbelem *g)
int gbelem_type
size_t exp_size
int stats_ngcd1
void remove_gb()
int find_good_term_divisor_ZZ(mpz_srcptr c, exponents_t e, int x, int degf, int &result_gap)
int first_in_degree
void collect_syzygy(gbvector *fsyz)
const RingElement * hf_orig
int spair_set_determine_next_degree(int &nextdegree)
The default Groebner basis computation class.
static int coeff_of(const RingElement *h, int deg)
Definition hilb.cpp:704
static RingElement * hilbertNumerator(const Matrix *M)
Definition hilb.cpp:665
Definition mem.hpp:78
@ PRINT_SPAIR_TRACKING
ComputationStatusCode
Definition computation.h:53
@ COMP_DONE_MIN_GENS
Definition computation.h:68
@ COMP_DONE_PAIR_LIMIT
Definition computation.h:64
@ COMP_DONE
Definition computation.h:60
@ COMP_DONE_SUBRING_LIMIT
Definition computation.h:70
@ COMP_ERROR
Definition computation.h:56
@ COMP_DONE_GB_LIMIT
Definition computation.h:65
@ COMP_DONE_DEGREE_LIMIT
Definition computation.h:61
@ COMP_DONE_CODIM
Definition computation.h:67
@ COMP_DONE_SYZ_LIMIT
Definition computation.h:66
@ COMP_COMPUTING
Definition computation.h:71
@ COMP_NOT_STARTED
Definition computation.h:58
@ COMP_INTERRUPTED
Definition computation.h:57
int error()
Definition error.c:48
#define Matrix
Definition factory.cpp:14
void gb(IntermediateBasis &F, int n)
RingZZ * globalZZ
Definition relem.cpp:13
static unsigned long nsaved_unneeded
static bool exponents_divide(int nvars, exponents_t a, exponents_t b)
static bool exponents_less_than(int nvars, exponents_t a, exponents_t b)
static unsigned long nloops
static void exponents_lcm(int nvars, int dega, exponents_t a, exponents_t b, exponents_t result, M2_arrayint weights, int &result_degree)
#define PrintingDegree
static bool exponents_equal(int nvars, exponents_t a, exponents_t b)
static unsigned long ncalls
const int ELEM_MINGB
const int ELEM_MINGEN
const int ELEM_IN_RING
gbA — the engine's default Buchberger-style Groebner-basis algorithm.
GBWeight — packed-weight evaluator that drives S-pair selection.
int p
Hilbert-series numerator via the Bigatti-Caboara-Robbiano recursion.
bool system_interrupted()
system_interrupted() — thread-safe polling predicate for Ctrl+C handling.
void size_t s
Definition m2-mem.cpp:271
const int ERROR
Definition m2-mem.cpp:55
VALGRIND_MAKE_MEM_DEFINED & result(result)
char newline[]
Definition m2-types.cpp:49
int M2_gbTrace
Definition m2-types.cpp:52
char M2_bool
Definition m2-types.h:82
MatrixConstructor — the mutable builder that produces an immutable Matrix.
Matrix — the engine's immutable homomorphism F -> G between free modules.
#define ALLOCATE_EXPONENTS(byte_len)
Definition monoid.hpp:62
#define EXPONENT_BYTE_SIZE(nvars)
Definition monoid.hpp:63
QuickSorter<Sorter> — ring-agnostic in-place sort over a duck-typed adapter.
#define VECTOR(T)
Definition newdelete.hpp:78
our_new_delete — per-class opt-in routing of new / delete through bdwgc.
volatile int x
#define POLY(q)
Definition poly.cpp:23
PolynomialRing — abstract polynomial-ring base, the engine's most-reused class.
ReducedGB — abstract base for the canonicalising reduction pass that follows GB computation.
RingElement — tagged (Ring*, ring_elem) pair, the engine's universal element type.
#define ZERO_RINGELEM
Definition ring.hpp:677
TermIterator< Nterm > end(Nterm *)
Definition ringelem.cpp:5
Doubly-linked-list node of a MonomialTable's per-component monomial list.
Definition montable.hpp:109
MonomialTable::mon_term plus an _coeff slot pointing at the entry's leading ZZ coefficient (or nullpt...
gbvector * fsyz
Definition gbring.hpp:99
gbvector * f
Definition gbring.hpp:98
spair * spair_last_deferred
spair * spair_list
spair * gen_last_deferred
gbelem_type minlevel
exponents_t lead
gbvector * lead_of_spoly
union gbA::spair::@344103323053032064111352014125043204306347255347 x
spair * next
struct gbA::spair::@344103323053032064111352014125043204306347255347::pair pair
exponents_t lcm
ring_elem coeff
Definition gbring.hpp:81
gbvector * next
Definition gbring.hpp:80
int monom[1]
Definition gbring.hpp:83
int comp
Definition gbring.hpp:82
const int EQ
Definition style.hpp:40
const int GT
Definition style.hpp:41
const int LT
Definition style.hpp:39
#define INTSIZE(a)
Definition style.hpp:37
void emit_wrapped(const char *s)
Definition text-io.cpp:27
void emit_line(const char *s)
Definition text-io.cpp:47
void emit(const char *s)
Definition text-io.cpp:41
Text-formatting helpers layered on buffer: bignum print, line wrapping, M2_gbTrace-gated emit.
mpz_srcptr get_mpz() const
Definition ringelem.hpp:127