Macaulay2 Engine
Loading...
Searching...
No Matches
montableZZ.cpp
Go to the documentation of this file.
1#include "montableZZ.hpp"
2#include <functional>
3#include <algorithm>
4#include <assert.h>
5
6/********************/
7/* Support routines */
8/********************/
9
10#if 0
11// static bool exponents_equal(int nvars, exponents_t a, exponents_t b)
12// {
13// for (int i=0; i<nvars; i++)
14// if (a[i] != b[i]) return false;
15// return true;
16// }
17#endif
18
19static bool exponents_greater(int nvars, exponents_t a, exponents_t b)
20{
21 for (int i = 0; i < nvars; i++)
22 {
23 if (a[i] < b[i]) return false;
24 if (a[i] > b[i]) return true;
25 }
26 return false;
27}
28
29static void exponents_show(FILE *fil, exponents_t exp, int nvars)
30/* This is only for debugging */
31{
32 fprintf(fil, "[");
33 for (int i = 0; i < nvars; i++) fprintf(fil, "%d ", exp[i]);
34 fprintf(fil, "]");
35}
36
37static unsigned long monomial_mask(int nvars, exponents_t exp)
38{
39 unsigned long result = 0;
40 int i, j;
41 for (i = 0, j = 0; i < nvars; i++, j++)
42 {
43 if (j == 8 * sizeof(long)) j = 0;
44 if (exp[i] > 0) result |= (1 << j);
45 }
46 return result;
47}
48
49/********************/
50/* MonomialTableZZ ****/
51/********************/
52
54{
55 mon_term *t = new mon_term;
56 t->_next = t->_prev = t;
57 t->_val = -1;
58 t->_lead = nullptr;
59 t->_coeff = nullptr;
60 return t;
61}
62
64{
67 result->_nvars = nvars;
68 result->_count = 0;
69 /* The first entry is a dummy entry. Components
70 will always start at 1. */
71 result->_head.push_back(nullptr);
72
73 return result;
74}
75
77{
78 // Nothing needs to be freed: garbage collection will clean
79 // it all out.
80}
81
82#if 0
83// NEW FUNCTION, 5/21/09. If not functional in a few days, remove it!
84int MonomialTableZZ::find_divisors(int max,
85 mpz_t coeff,
86 exponents_t exp,
87 int comp,
88 VECTOR(int) *result_term_divisors,
89 VECTOR(int) *result_mon_divisors) const,
90 /* max: the max number of divisors to find.
91 exp: the monomial whose divisors we seek.
92 result: an array of mon_term's.
93 return value: length of this array, i.e. the number of matches found */
94{
95 assert(comp >= 1);
96 if (comp >= static_cast<int>(_head.size())) return 0;
97 mon_term *head = _head[comp];
98 mon_term *t;
99 int i;
100
101 int nmatches = 0;
102 unsigned long expmask = ~(monomial_mask(_nvars, exp));
103
104 for (t = head->_next; t != head; t = t->_next)
105 if ((expmask & t->_mask) == 0)
106 {
107 bool is_div = 1;
108 for (i=0; i<_nvars; i++)
109 if (exp[i] < t->_lead[i])
110 {
111 is_div = 0;
112 break;
113 }
114 if (is_div)
115 {
116 if (mpz_divisible_p(coeff, t->_coeff))
117 {
118 n_term_matches++;
119 if (result_term_divisors != 0) result_term_divisors->push_back(t->_val);
120 }
121 else if (result_mon_divisors != 0) result_mon_divisors->push_back(t->_val);
122
123 }
124 if (is_div && mpz_divisible_p(coeff,t->_coeff))
125 {
126 nmatches++;
127 if (result != 0) result->push_back(t);
128 if (max >= 0 && nmatches >= max) break;
129 }
130 }
131 if (M2_gbTrace == 15 && nmatches >= 2)
132 {
133 buffer o;
134 o << "find_term_divisors called on ";
135 show_mon_term(o, coeff, exp, comp);
136 o << " #matches=" << nmatches << newline;
137 if (result != 0)
138 for (int i=0; i<result->size(); i++)
139 show_mon_term(stderr, (*result)[i]);
140 }
141 return nmatches;
142}
143#endif
144
146 mpz_srcptr coeff,
147 exponents_t exp,
148 int comp,
149 VECTOR(mon_term *) * result) const
150/* max: the max number of divisors to find.
151 exp: the monomial whose divisors we seek.
152 result: an array of mon_term's.
153 return value: length of this array, i.e. the number of matches found */
154{
155 assert(comp >= 1);
156 if (comp >= static_cast<int>(_head.size())) return 0;
157 mon_term *head = _head[comp];
158 mon_term *t;
159
160 int nmatches = 0;
161 unsigned long expmask = ~(monomial_mask(_nvars, exp));
162
163 for (t = head->_next; t != head; t = t->_next)
164 if ((expmask & t->_mask) == 0)
165 {
166 bool is_div = 1;
167 for (int i = 0; i < _nvars; i++)
168 if (exp[i] < t->_lead[i])
169 {
170 is_div = 0;
171 break;
172 }
173 if (is_div && mpz_divisible_p(coeff, t->_coeff))
174 {
175 nmatches++;
176 if (result != nullptr) result->push_back(t);
177 if (max >= 0 && nmatches >= max) break;
178 }
179 }
180 if (M2_gbTrace == 15 && nmatches >= 2)
181 {
182 buffer o;
183 o << "find_term_divisors called on ";
184 show_mon_term(o, coeff, exp, comp);
185 o << " #matches=" << nmatches << newline;
186 if (result != nullptr)
187 for (int i = 0; i < result->size(); i++) show_mon_term(o, (*result)[i]);
188 o << newline;
189 }
190 return nmatches;
191}
192
193bool MonomialTableZZ::is_weak_member(mpz_srcptr c, exponents_t exp, int comp) const
194// Is [c,exp,comp] in the submodule generated by the terms in 'this'?
195// Maybe a gbvector should be returned?
196{
197 // Loop through the elements of component 'comp'
198 // If that exponent vector is <= 'exp', then set g (eventual gcd) (if not
199 // set).
200 // else mpz(g,g,...);
201 // if mpz_divisible_p(c,g): return true
202 // At the end, return false
203
204 assert(comp >= 1);
205 if (comp >= static_cast<int>(_head.size())) return 0;
206 mon_term *head = _head[comp];
207 mon_term *t;
208 int i;
209
210 unsigned long expmask = ~(monomial_mask(_nvars, exp));
211 mpz_t g;
212 bool g_is_set = false;
213 for (t = head->_next; t != head; t = t->_next)
214 if ((expmask & t->_mask) == 0)
215 {
216 bool is_div = true;
217 for (i = 0; i < _nvars; i++)
218 if (exp[i] < t->_lead[i])
219 {
220 is_div = false;
221 break;
222 }
223 if (!is_div) continue;
224 if (!g_is_set)
225 {
226 mpz_init_set(g, t->_coeff);
227 g_is_set = true;
228 }
229 else
230 mpz_gcd(g, g, t->_coeff);
231 /* g is set */
232 if (mpz_divisible_p(c, g))
233 {
234 mpz_clear(g);
235 return true;
236 }
237 }
238 if (g_is_set) mpz_clear(g);
239 return false;
240}
241
242bool MonomialTableZZ::is_strong_member(mpz_srcptr c, exponents_t exp, int comp) const
243{
244 return (find_term_divisors(1, c, exp, comp, nullptr) > 0);
245}
246
248{
249 assert(comp >= 1);
250 if (comp >= static_cast<int>(_head.size())) return -1;
251 mon_term *head = _head[comp];
252 mon_term *t;
253
254 int smallest_val = -1;
255 mpz_srcptr smallest = nullptr;
256
257 unsigned long expmask = ~(monomial_mask(_nvars, exp));
258
259 for (t = head->_next; t != head; t = t->_next)
260 if ((expmask & t->_mask) == 0)
261 {
262 bool is_div = 1;
263 for (int i = 0; i < _nvars; i++)
264 if (exp[i] < t->_lead[i])
265 {
266 is_div = 0;
267 break;
268 }
269 if (is_div)
270 {
271 if (smallest_val < 0 || (mpz_cmpabs(smallest, t->_coeff) > 0))
272 {
273 smallest_val = t->_val;
274 smallest = t->_coeff;
275 }
276 }
277 }
278 return smallest_val;
279}
280
282 exponents_t exp,
283 int comp,
284 VECTOR(mon_term *) * result) const
285{
286 assert(comp >= 1);
287 if (comp >= static_cast<int>(_head.size())) return 0;
288 mon_term *head = _head[comp];
289 mon_term *t;
290
291 int nmatches = 0;
292 unsigned long expmask = ~(monomial_mask(_nvars, exp));
293
294 for (t = head->_next; t != head; t = t->_next)
295 if ((expmask & t->_mask) == 0)
296 {
297 bool is_div = 1;
298 for (int i = 0; i < _nvars; i++)
299 if (exp[i] < t->_lead[i])
300 {
301 is_div = 0;
302 break;
303 }
304 if (is_div)
305 {
306 nmatches++;
307 if (result != nullptr) result->push_back(t);
308 if (max >= 0 && nmatches >= max) break;
309 }
310 }
311
312 if (M2_gbTrace == 15 && nmatches >= 2)
313 {
314 buffer o;
315 o << "find_monomial_divisors called on ";
316 show_mon_term(o, nullptr, exp, comp);
317 o << " #matches=" << nmatches << newline;
318 if (result != nullptr)
319 for (int i = 0; i < result->size(); i++) show_mon_term(o, (*result)[i]);
320 o << newline;
321 }
322 return nmatches;
323}
324
326 exponents_t exp,
327 int comp) const
328{
329 if (comp >= static_cast<int>(_head.size())) return nullptr;
330 mon_term *head = _head[comp];
331 mon_term *t;
332 int i;
333
334 unsigned long expmask = monomial_mask(_nvars, exp);
335
336 for (t = head->_next; t != head; t = t->_next)
337 if (expmask == t->_mask)
338 {
339 bool is_eq = 1;
340 for (i = 0; i < _nvars; i++)
341 if (exp[i] != t->_lead[i])
342 {
343 is_eq = 0;
344 break;
345 }
346 if (is_eq && !mpz_cmp(coeff, t->_coeff)) return t;
347 }
348 return nullptr;
349}
350
352 exponents_t exp,
353 int comp,
354 int first_val) const
355{
356 if (comp >= static_cast<int>(_head.size())) return nullptr;
357 mon_term *head = _head[comp];
358 mon_term *t;
359 int i;
360
361 mon_term *result = nullptr;
362 int neqs = 0;
363
364 unsigned long expmask = monomial_mask(_nvars, exp);
365
366 for (t = head->_next; t != head; t = t->_next)
367 {
368 if (t->_val < first_val) continue;
369 if (expmask == t->_mask)
370 {
371 bool is_eq = 1;
372 for (i = 0; i < _nvars; i++)
373 if (exp[i] != t->_lead[i])
374 {
375 is_eq = 0;
376 break;
377 }
378 if (is_eq)
379 {
380 if (result == nullptr) result = t;
381 neqs++;
382 }
383 }
384 }
385 if (neqs > 1)
386 {
387 printf("number of exact matches: %d\n", neqs);
388 }
389 return result;
390}
391
393 mpz_srcptr new_coeff,
394 int new_id)
395{
396 t->_coeff = new_coeff; // WARNING: new_coeff had better outlive the use of this element.
397 t->_val = new_id;
398}
399
400void MonomialTableZZ::insert(mpz_srcptr coeff, exponents_t exp, int comp, int id)
401{
402 /* Insert 'exp' into the monomial table. These are kept sorted in ascending
403 order
404 in some order (lex order?). No element is ever removed.
405 */
406
407 if (comp >= INTSIZE(_head))
408 {
409 for (int i = INTSIZE(_head); i <= comp; i++)
410 _head.push_back(make_list_head());
411 }
412
413 mon_term *head = _head[comp];
414 mon_term *t;
415
416 /* Make a new mon_term including exp */
417 mon_term *newterm = new mon_term;
418 newterm->_lead = exp;
419 newterm->_mask = monomial_mask(_nvars, exp);
420 newterm->_val = id;
421 newterm->_coeff = coeff;
422 _count++;
423
424 /* Find where to put it */
425 for (t = head; t->_next != head; t = t->_next)
426 {
427 if (exponents_greater(_nvars, newterm->_lead, t->_next->_lead))
428 {
429 /* Time to insert newterm, right between t, t->next */
430 break;
431 }
432 }
433
434 /* The actual insertion */
435 newterm->_next = t->_next;
436 newterm->_prev = t;
437 t->_next->_prev = newterm;
438 t->_next = newterm;
439}
440
441/****************************
442 * Minimalization ***********
443 ****************************/
444
446{
447 int nvars;
448 const VECTOR(mpz_srcptr) & coeffs;
449 const VECTOR(exponents_t) & exps;
450 const VECTOR(int) & comps;
452 const VECTOR(mpz_srcptr) & coeffs0,
453 const VECTOR(exponents_t) & exps0,
454 const VECTOR(int) & comps0)
455 : nvars(nvars0), coeffs(coeffs0), exps(exps0), comps(comps0)
456 {
457 }
458
459 bool operator()(int x, int y)
460 {
461 exponents_t xx = exps[x];
462 exponents_t yy = exps[y];
463 for (int i = 0; i < nvars; i++)
464 if (xx[i] < yy[i])
465 return true;
466 else if (xx[i] > yy[i])
467 return false;
468 if (comps[x] < comps[y])
469 return true;
470 else if (comps[x] > comps[y])
471 return false;
472 // Now order them in ascending order on the coeff (which should always be
473 // POSITIVE).
474 return (mpz_cmp(coeffs[x], coeffs[y]) < 0);
475 }
476
477#if 0
478// bool operator()(int x, int y) {
479// int result = 0; // -1 is false, 1 is true
480// exponents_t xx = exps[x];
481// exponents_t yy = exps[y];
482// for (int i=0; i<nvars; i++)
483// if (xx[i] < yy[i]) {result = 1; break;}
484// else if (xx[i] > yy[i]) {result = -1; break;}
485// if (result == 0)
486// if (comps[x] < comps[y]) result = 1;
487// else if (comps[x] > comps[y]) result = -1;
488// if (result == 0)
489// // Now order them in ascending order on the coeff (which should always be POSITIVE).
490// result = (mpz_cmp(coeffs[x],coeffs[y]) > 0);
491// fprintf(stderr, "comparing %d and %d. Result: %d\n",x,y,result);
492// if (result > 0) return true; else return false;
493// }
494#endif
495};
496
498 mpz_srcptr coeff,
499 exponents_t exp,
500 int comp,
501 int val) const
502{
503 fprintf(fil, " elem coeff=");
504 mpz_out_str(fil, 10, coeff);
505 fprintf(fil, " exp=");
506 exponents_show(fil, exp, _nvars);
507 fprintf(fil, " comp=");
508 fprintf(fil, "%d", comp);
509 fprintf(fil, " val=");
510 fprintf(fil, "%d\n", val);
511}
512
514 const VECTOR(mpz_srcptr) & coeffs,
515 const VECTOR(exponents_t) & exps,
516 const VECTOR(int) & comps,
517 VECTOR(int) & result_positions,
518 bool use_stable_sort)
519{
520 // Find a set of elements which generate all of them, as a submodule.
521 // The indices for these are placed into result_positions.
522
523 // The plan for this is simple, although it could be easily optimized.
524 // First, sort the elements into increasing order, with coeffs for each
525 // specific
526 // exponent vector also in increasing order (ASSUMPTION: all coeffs are > 0).
527
528 // Second, loop through each one, checking whether it is in the submodule gen
529 // by the previous.
531
532#if 0
533 // debugging
534 if (coeffs.size() != exps.size())
535 fprintf(stderr, "size mismatch\n");
536 if (coeffs.size() != exps.size())
537 fprintf(stderr, "size mismatch2\n");
538 if (coeffs.size() != comps.size())
539 fprintf(stderr, "size mismatch3\n");
540#endif
541#if 0
542 // debugging
543 fprintf(stderr, "-------------\n");
544 fprintf(stderr, "find_weak_generators %ld\n", coeffs.size());
545 for (size_t i = 0; i < coeffs.size(); i++)
546 T->show_weak(stderr, coeffs[i], exps[i], comps[i], i);
547#endif
548
549 VECTOR(int) positions;
550 positions.reserve(exps.size());
551 for (unsigned int i = 0; i < exps.size(); i++) positions.push_back(i);
552
553 /* The following sorts in ascending lex order, considering the component, exp
554 vector
555 and finally the coefficient */
556 if (use_stable_sort)
557 std::stable_sort(positions.begin(),
558 positions.end(),
559 montable_sorter_ZZ(nvars, coeffs, exps, comps));
560 else
561 std::sort(positions.begin(),
562 positions.end(),
563 montable_sorter_ZZ(nvars, coeffs, exps, comps));
564
565#if 0
566 // debugging
567 fprintf(stderr, "sorted find_weak_generators\n");
568 for (size_t i = 0; i < coeffs.size(); i++)
569 T->show_weak(stderr, coeffs[i], exps[i], comps[i], positions[i]);
570#endif
571
572#if 0
573// fprintf(stderr, "sorted terms: ");
574// for (int i=0; i<positions.size(); i++)
575// fprintf(stderr, "%d ", positions[i]);
576// fprintf(stderr, "\n");
577#endif
578
579 for (VECTOR(int)::iterator j = positions.begin(); j != positions.end(); j++)
580 if (!T->is_weak_member(coeffs[*j], exps[*j], comps[*j]))
581 {
582 result_positions.push_back(*j);
583 T->insert(coeffs[*j], exps[*j], comps[*j], *j);
584 }
585
586#if 0
587 // debugging
588 fprintf(stderr, "ones we take: find_weak_generators %ld\n", coeffs.size());
589 for (size_t i = 0; i < result_positions.size(); i++)
590 T->show_weak(stderr,
591 coeffs[result_positions[i]],
592 exps[result_positions[i]],
593 comps[result_positions[i]],
594 result_positions[i]);
595 fprintf(stderr, "\n\n");
596#endif
597 /* We could return T if that is desired */
598 // freemem(T);
599}
600
602 const VECTOR(mpz_srcptr) & coeffs,
603 const VECTOR(exponents_t) & exps,
604 const VECTOR(int) & comps,
605 VECTOR(int) & result_positions)
606{
607 // Find the set of terms c*exp*comp such that every other one is divisible
608 // by at least one of these.
609
610 VECTOR(int) positions;
611 positions.reserve(exps.size());
612 for (unsigned int i = 0; i < exps.size(); i++) positions.push_back(i);
613
614 /* The following sorts in ascending lex order, considering the component, exp
615 vector
616 and finally the coefficient */
617 std::stable_sort(positions.begin(),
618 positions.end(),
619 montable_sorter_ZZ(nvars, coeffs, exps, comps));
620
621#if 0
622// fprintf(stderr, "sorted terms: ");
623// for (int i=0; i<positions.size(); i++)
624// fprintf(stderr, "%d ", positions[i]);
625// fprintf(stderr, "\n");
626#endif
627
629 for (VECTOR(int)::iterator j = positions.begin(); j != positions.end(); j++)
630 if (!T->is_strong_member(coeffs[*j], exps[*j], comps[*j]))
631 {
632 result_positions.push_back(*j);
633 T->insert(coeffs[*j], exps[*j], comps[*j], *j);
634 }
635 /* We could return T if that is desired */
636 // freemem(T);
637}
638
640{
641 buffer o;
642 show_mon_term(o, t);
643 fprintf(fil, "%s", o.str());
644}
645
647{
648 show_mon_term(o, t->_coeff, t->_lead, t->_val);
649}
650
652 mpz_srcptr coeff,
653 exponents_t lead,
654 int comp) const
655{
656 if (coeff != nullptr)
657 {
658 char s[100000];
659 mpz_get_str(s, 10, coeff);
660 o << s;
661 }
662 if (_nvars == 0)
663 o << "[";
664 else
665 {
666 o << "[" << lead[0];
667 for (int i = 1; i < _nvars; i++) o << "," << lead[i];
668 }
669 o << "] (" << comp << ")" << newline;
670}
671
672void MonomialTableZZ::show(FILE *fil) const
673{
674 mon_term *t, *head;
675 /* Loop through each component, display monomials(val) 10 per line */
676 fprintf(fil,
677 "monomial table: %d vars, %d components, %d elements\n",
678 this->_nvars,
679 static_cast<int>(_head.size()),
680 this->_count);
681 for (unsigned i = 1; i < _head.size(); i++)
682 {
683 head = this->_head[i];
684 if (head->_next == head) continue;
685 fprintf(fil, " -- component %d --\n", i);
686 for (t = head->_next; t != head; t = t->_next)
687 {
688 show_mon_term(fil, t);
689 }
690 }
691 fprintf(fil, "\n");
692}
693
695// Local Variables:
696// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
697// indent-tabs-mode: nil
698// End:
exponents::Exponents exponents_t
bool is_strong_member(mpz_srcptr c, exponents_t exp, int comp) const
mon_term * find_exact_monomial(exponents_t exp, int comp, int first_val) const
static mon_term * make_list_head()
void insert(mpz_srcptr coeff, exponents_t exp, int comp, int id)
static MonomialTableZZ * make(int nvars)
void show_mon_term(FILE *fil, mon_term *t) const
void change_coefficient(mon_term *t, mpz_srcptr new_coeff, int new_id)
bool is_weak_member(mpz_srcptr c, exponents_t exp, int comp) const
static void find_strong_generators(int nvars, const VECTOR(mpz_srcptr) &coeffs, const VECTOR(exponents_t) &exps, const VECTOR(int) &comps, VECTOR(int) &result_positions)
void show(FILE *fil) const
int find_smallest_coeff_divisor(exponents_t exp, int comp) const
int find_monomial_divisors(int max, exponents_t exp, int comp, VECTOR(mon_term *) *result=nullptr) const
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)
mon_term * find_exact(mpz_srcptr coeff, exponents_t exp, int comp) const
void show_weak(FILE *fil, mpz_srcptr coeff, exponents_t exp, int comp, int val) const
int find_term_divisors(int max, mpz_srcptr coeff, exponents_t exp, int comp, VECTOR(mon_term *) *result=nullptr) const
MonomialTable analogue for monomials carrying a ZZ coefficient.
char * str()
Definition buffer.hpp:72
void size_t s
Definition m2-mem.cpp:271
VALGRIND_MAKE_MEM_DEFINED & result(result)
char newline[]
Definition m2-types.cpp:49
int M2_gbTrace
Definition m2-types.cpp:52
static void exponents_show(FILE *fil, exponents_t exp, int nvars)
Definition montable.cpp:34
static unsigned long monomial_mask(int nvars, exponents_t exp)
static bool exponents_greater(int nvars, exponents_t a, exponents_t b)
static void exponents_show(FILE *fil, exponents_t exp, int nvars)
MonomialTableZZ — coefficient-aware leading-monomial index for ZZ-coefficient Groebner bases.
#define VECTOR(T)
Definition newdelete.hpp:78
volatile int x
#define max(a, b)
Definition polyroots.cpp:52
MonomialTable::mon_term plus an _coeff slot pointing at the entry's leading ZZ coefficient (or nullpt...
const VECTOR(mpz_srcptr) &coeffs
bool operator()(int x, int y)
const VECTOR(int) &comps
montable_sorter_ZZ(int nvars0, const VECTOR(mpz_srcptr) &coeffs0, const VECTOR(exponents_t) &exps0, const VECTOR(int) &comps0)
const VECTOR(exponents_t) &exps
#define INTSIZE(a)
Definition style.hpp:37
#define T
Definition table.c:13