Macaulay2 Engine
Loading...
Searching...
No Matches
monideal.cpp
Go to the documentation of this file.
1// Copyright 1994-2021 Michael E. Stillman
2
3// TODO MES:
4// rename Nmi_node
5// rename new_mi_node
6// remove union in the Nmi_node: Baggage, down pointers will always be there.
7// sat: do not loop if J is 0 or 1!
8// perhaps first call radical on J? (or is this being done in m2 code?)
9// rewrite delete of a MonomialIdeal
10// MonomialIdeal ==> rename to e.g. MonomialLookupTable
11// A MonomialIdeal should be an engine object, which contains a MonomialLookupTable, and a ring.
12// Maybe:
13// MonomialLookupTable
14// some functions in a namespace, otherwise global, that compute sat, quotient, radical, etc.
15// MonomialIdeal: engine object which is interned, and the monomial ideal is deleted on finalization.
16// Memory layout for this data structure?
17#include "monideal.hpp"
18
19#include <iostream>
20#include <algorithm>
21
22#include "ExponentList.hpp"
23#include "ExponentVector.hpp"
24#include "debug.hpp"
25#include "monoid.hpp"
26#include "text-io.hpp"
27
29{
30 // Incorporate the size and the first 5 elements
31 unsigned int hashval = size();
32 int count = 0;
33 for (Bag& b : *this)
34 {
35 if (count >= 5) break;
36 const_varpower m = b.monom().data();
37 hashval = 4436435 * hashval + varpower::computeHashValue(m);
38 count++;
39 }
40 return hashval;
41}
42
44{
46 if ((count % 2) == 1) delete mi_stash;
47}
48
50{
51 Nmi_node *p = reinterpret_cast<Nmi_node *>(mi_stash->new_elem());
52 p->var = v;
53 p->exp = e;
54 p->left = nullptr;
55 p->right = nullptr;
56 p->header = nullptr;
57 p->tag = Nmi_node::node;
58 p->val.down = d;
59 return p;
60}
61
63{
64 Nmi_node *p = reinterpret_cast<Nmi_node *>(mi_stash->new_elem());
65 p->var = v;
66 p->exp = e;
67 p->left = nullptr;
68 p->right = nullptr;
69 p->header = nullptr;
70 p->tag = Nmi_node::leaf;
71 p->val.bag = b;
72 return p;
73}
74
75// TODO: this is recursive, not so good for large monomial ideals!
76// So replace this with something iterative.
77// Really: should be named: delete_monideal_tree or something like that...
79{
80 if (p == nullptr) return;
81 if (p->right != p->header) delete_mi_node(p->right);
82 if (p->tag == Nmi_node::node)
83 {
84 if (p->header != p) delete_mi_node(p->down());
85 }
86 else
87 delete p->baggage();
88 mi_stash->delete_elem(p);
89}
90
92 : R(RR), mi(nullptr), count(0), mi_stash(mi_stash0)
93{
94 if (mi_stash == nullptr)
95 {
96 count = 1;
97 mi_stash = new stash("mi_node", sizeof(Nmi_node));
98 }
99}
100
101
103 VECTOR(Bag *) &elems, // we now own these elements
104 VECTOR(Bag *) &rejects, // except for the ones we place into here
105 stash *mi_stash0)
106 : R(R0), mi(nullptr), count(0), mi_stash(mi_stash0)
107{
108 if (mi_stash == nullptr)
109 {
110 count = 1;
111 mi_stash = new stash("mi_node", sizeof(Nmi_node));
112 }
113
114 // create a vector of <simple degree, index> for each element of 'elems'.
115 // sort them in increasing simple degree.
116 // then loop through, adding them in. This will insure that we only add in
117 // minimal generators.
118
119 std::vector<std::pair<int, int>> degs_and_indices;
120 int count = 0;
121 for (auto& b : elems)
122 {
123 int deg = varpower::simple_degree(b->monom().data());
124 degs_and_indices.push_back(std::make_pair(deg, count));
125 ++count;
126 }
127 std::stable_sort(degs_and_indices.begin(), degs_and_indices.end());
128
129 for (auto p : degs_and_indices)
130 {
131 Bag* b = elems[p.second];
132 Bag* b1; // not used here...
133 if (search(b->monom().data(), b1))
134 rejects.push_back(b);
135 else
137 }
138}
139
141 VECTOR(Bag *) &elems, // we now own these elements
142 stash *mi_stash0)
143 : R(R0), mi(nullptr), count(0), mi_stash(mi_stash0)
144{
145 if (mi_stash == nullptr)
146 {
147 count = 1;
148 mi_stash = new stash("mi_node", sizeof(Nmi_node));
149 }
150
151 // create a vector of <simple degree, index> for each element of 'elems'.
152 // sort them in increasing simple degree.
153 // then loop through, adding them in. This will insure that we only add in
154 // minimal generators.
155
156 std::vector<std::pair<int, int>> degs_and_indices;
157 int count = 0;
158 for (auto& b : elems)
159 {
160 int deg = varpower::simple_degree(b->monom().data());
161 degs_and_indices.push_back(std::make_pair(deg, count));
162 ++count;
163 }
164 std::stable_sort(degs_and_indices.begin(), degs_and_indices.end());
165
166 for (auto p : degs_and_indices)
167 {
168 Bag* b = elems[p.second];
169 Bag* b1; // not used here...
170 if (search(b->monom().data(), b1))
171 delete b;
172 else
174 }
175}
176
178{
179 return first_node()->monom().data();
180}
181
183{
184 return next(first_node())->monom().data();
185}
186
188{
190 for (auto& b : *this)
191 result->insert_minimal(new Bag(b));
192 return result;
193}
194
196{
197 if (this == &mi0) return true;
198 if (size() != mi0.size()) return false;
199 Iterator i = begin();
200 Iterator j = mi0.begin();
201 Iterator sentinel = end();
202 while (i != sentinel)
203 {
204 const_varpower m = (*i).monom().data();
205 const_varpower n = (*j).monom().data();
206 if (!varpower::is_equal(m, n)) return false;
207 i++;
208 j++;
209 }
210 GC_reachable_here(&mi0);
211 return true;
212}
213
215{
216 if (mi == nullptr) return 0;
217
218 Nmi_node *p = mi;
219
220 for (;;)
221 {
222 p = p->right;
223
224 if (p == p->header)
225 {
226 if ((p = p->down()) == nullptr) return 0;
227 continue;
228 }
229
230 if (p->exp > exp[p->var])
231 {
232 if ((p = p->header->down()) == nullptr) return 0;
233 continue;
234 }
235
236 if (p->tag == Nmi_node::leaf)
237 {
238 b = p->baggage();
239 return 1;
240 }
241
242 p = p->down();
243 }
244}
245
247{
248 b.clear();
249 if (mi == nullptr) return;
250
251 Nmi_node *p = mi;
252
253 for (;;)
254 {
255 p = p->right;
256
257 if (p == p->header)
258 {
259 if ((p = p->down()) == nullptr) return;
260 continue;
261 }
262
263 if (p->exp > exp[p->var])
264 {
265 if ((p = p->header->down()) == nullptr) return;
266 continue;
267 }
268
269 if (p->tag == Nmi_node::leaf)
270 {
271 b.push_back(p->baggage());
272 }
273 else
274 p = p->down();
275 }
276}
277
279{
280 exponents_t exp = ARRAY_ON_STACK(int, get_ring()->n_vars());
281 varpower::to_expvector(get_ring()->n_vars(), m, exp);
282 return search_expvector(exp, b);
283}
284
286{
287 while (p != nullptr)
288 {
289 p = p->left;
290 if (p->tag == Nmi_node::leaf)
291 return p;
292 else
293 p = p->down();
294 }
295 return nullptr;
296}
297
298void *MonomialIdeal::next(void *p) const
299{
300 return reinterpret_cast<void *>(next(reinterpret_cast<Nmi_node *>(p)));
301}
302
304{
305 while (p != nullptr)
306 {
307 p = p->right;
308 if (p->tag == Nmi_node::leaf)
309 return p;
310 else
311 p = p->down();
312 }
313 return nullptr;
314}
315
316void *MonomialIdeal::prev(void *p) const
317{
318 return reinterpret_cast<void *>(prev(reinterpret_cast<Nmi_node *>(p)));
319}
320
322{
323 Nmi_node **p = &top, *up = nullptr;
324 int one_element = 1;
325
326 for (index_varpower i = b->monom().data(); i.valid();)
327 {
328 one_element = 0;
329 int insert_var = i.var();
330 int insert_exp;
331
332 if (*p == nullptr)
333 {
334 // make a new header node
335 *p = new_internal_mi_node(insert_var, 0, up);
336 (*p)->header = (*p)->left = (*p)->right = *p;
337 }
338 else if ((*p)->var < insert_var)
339 {
340 // make a new layer
341 Nmi_node *header_node, *zero_node;
342 header_node = new_internal_mi_node(insert_var, 0, up);
343 zero_node = new_internal_mi_node(insert_var, 0, *p);
344
345 header_node->left = header_node->right = zero_node;
346 (*p)->down() = zero_node;
347 *p = header_node->header = zero_node->header = zero_node->left =
348 zero_node->right = header_node;
349 }
350
351 if ((*p)->var > insert_var)
352 {
353 insert_var = (*p)->var;
354 insert_exp = 0;
355 }
356 else
357 {
358 insert_exp = i.exponent();
359 ++i;
360 }
361
362 Nmi_node *q = (*p)->right;
363 while ((q != q->header) && (q->exp < insert_exp)) q = q->right;
364 if (q->exp != insert_exp)
365 {
366 Nmi_node *insert_node;
367
368 if (i.valid())
369 {
370 insert_node = new_internal_mi_node(
371 insert_var, insert_exp, static_cast<Nmi_node*>(nullptr));
372 q->insert_to_left(insert_node);
373 q = insert_node;
374 }
375 else
376 {
377 insert_node = new_leaf_mi_node(insert_var, insert_exp, b);
378 q->insert_to_left(insert_node);
379 return;
380 }
381 }
382
383 up = q;
384 p = &(q->down());
385 }
386 if (one_element)
387 {
388 // insert a header node and a var/exp = 0/0 leaf
389 top = new_internal_mi_node(0, 0, static_cast<Nmi_node *>(nullptr));
390 Nmi_node *leaf_node = new_leaf_mi_node(0, 0, b);
391 top->left = top->right = leaf_node;
392 top->header = leaf_node->header = leaf_node->left = leaf_node->right =
393 top;
394 }
395}
396
398{
399 assert(p != nullptr);
400 assert(p->tag == Nmi_node::leaf);
401 p->baggage() = nullptr;
402 count -= 2;
403
404 for (; p != nullptr;)
405 {
406 p->left->right = p->right;
407 p->right->left = p->left;
408 Nmi_node *q = p->header;
409 p->left = p->right = nullptr;
411
412 if (q->right == q->header) // only the header is left, so delete it
413 {
414 p = q->down();
415 q->down() = nullptr;
416 if (p != nullptr) p->down() = nullptr;
418 continue;
419 }
420
421 if (q->left != q->right) return;
422
423 if (q->left->exp > 0) return;
424
425 Nmi_node *dad = q->down();
426 if (q->left->tag == Nmi_node::leaf)
427 {
428 // set parent of q to be a leaf with baggage of q->left
429 // since this is a leaf, dad should be non null
430 assert(dad != nullptr);
431 dad->tag = Nmi_node::leaf;
432 dad->baggage() = q->left->baggage();
433 }
434 else
435 {
436 // set parent of q to be node pointing to q->left->down
437 q->left->down()->down() = dad;
438 if (dad != nullptr)
439 dad->down() = q->left->down();
440 else
441 mi = q->left->down();
442 q->left->down() = nullptr;
443 }
444 q->down() = nullptr;
445 delete_mi_node(q); // Deletes both nodes q, q->left.
446 return;
447 }
448 if (p == nullptr) mi = nullptr;
449}
450
452{
453 Nmi_node *p = reinterpret_cast<Nmi_node *>(next(mi));
454 if (p == nullptr) return 0;
455 b = p->baggage();
456 remove1(p);
457 return 1;
458}
459
460static int nlists = 0;
461static int nleaves = 0;
462static int nnodes = 0;
463static int ndepth = 0;
464
465void MonomialIdeal::do_node(Nmi_node *p, int indent, int disp) const
466{
467 buffer o;
468 int i;
469 assert(p->left != nullptr);
470 assert(p->right != nullptr);
471 assert(p->left->right == p);
472 assert(p->right->left == p);
473 if (disp)
474 {
475 for (i = 1; i <= indent; i++) o << ' ';
476 o << p->var << ' ' << p->exp;
477 }
478 if (p->tag == Nmi_node::leaf)
479 {
480 nleaves++;
481 if (disp) o << ' ';
482 varpower::elem_text_out(o, p->baggage()->monom().data());
483 o << '(';
484 o << p->baggage()->basis_elem();
485 o << ')';
486 }
487 else if (p == p->header)
488 nlists++;
489 else
490 nnodes++;
491 emit_line(o.str());
492}
493
494void MonomialIdeal::do_tree(Nmi_node *p, int depth, int indent, int disp) const
495{
496 if (depth > ndepth) ndepth = depth;
497 do_node(p, indent, disp);
498 Nmi_node *q = p->right;
499 while (q != p)
500 {
501 do_node(q, indent, disp);
502 if (q->tag != Nmi_node::leaf)
503 do_tree(q->down(), depth + 1, indent + 2, disp);
504 q = q->right;
505 }
506}
507
508void MonomialIdeal::debug_out(int disp) const
509// Display MonomialIdeal in tree-like form, collect statistics
510{
511 nlists = 0;
512 nnodes = 0;
513 nleaves = 0;
514 ndepth = 0;
515 if (mi != nullptr) do_tree(mi, 0, 0, disp);
516 buffer o;
517 o << "list nodes = " << nlists << newline;
518 o << "internal nodes = " << nnodes << newline;
519 o << "monomials = " << nleaves << newline;
520 o << "max depth = " << ndepth << newline;
521 emit(o.str());
522}
523
525 const Nmi_node *const up) const
526// Returns the number of leaves at tree with root p.
527// Make sure that the list header is constructed ok, that the
528// left/right pointers are ok on this level, that the
529// var, exp, values in this train are correct.
530// Then loop through, checking each node (recursively) and each leaf
531{
532 Nmi_node *q;
533 // First check the node 'p' itself
534 assert(p != nullptr);
535 assert(p->var >= 0);
536 if (up != nullptr) assert(p->var < up->var);
537 assert(p->header == p);
538 assert(p->tag == Nmi_node::node);
539 assert(p->down() == up);
540 assert(p->left != nullptr);
541 assert(p->right != nullptr);
542
543 // Now loop through each element in left/right chain, checking that
544 // v, e, left, right values are consistent.
545 for (q = p->left; q != p; q = q->left)
546 {
547 assert(q->left != nullptr);
548 assert(q->right != nullptr);
549 assert(q->header == p);
550 assert(q->right->left == q);
551 assert(q->left->right == q);
552 assert(q->var == p->var);
553 assert((q->right == p) || (q->exp < q->right->exp));
554 assert(q->exp >= 0);
555 }
556
557 // Now loop through again, this time descending into nodes
558 int c = 0;
559 for (q = p->right; q != p; q = q->right)
560 if (q->tag == Nmi_node::node)
561 c += debug_check(q->down(), q);
562 else
563 c++;
564 return c;
565}
566
568{
569 if (count <= 1)
570 {
571 assert(mi == nullptr);
572 return;
573 }
574 assert(mi != nullptr);
575 assert(debug_check(mi, nullptr) == count / 2);
576}
577
579{
580 if (mi == nullptr) return true; // nothing else to check.
581
582 Nmi_node* p = mi;
583 while (p != nullptr)
584 {
585 // check the current node
586 if (p->left == nullptr) throw exc::engine_error("left node link is null");
587 if (p->right == nullptr) throw exc::engine_error("right node link is null");
588 if (p->header == nullptr) throw exc::engine_error("header node link is null");
589 if (p->tag == Nmi_node::node and p != mi and p->val.down == nullptr) throw exc::engine_error("down node link is null");
590
591 // now go to the next node
592 // if this is a leaf, go right.
593 // if this is a header, go down (up), and one left
594 // if this is an internal node, go down (to subtree).
595 if (p->tag == Nmi_node::node and p->header != p)
596 p = p->val.down;
597 else if (p->tag == Nmi_node::node and p->header == p)
598 {
599 // this is a header node (head of the double linked list at this level)
600 // Let's check all of the elements in the double ring at this level.
601 for (Nmi_node* q = p->right; q != p; q = q->right)
602 {
603 if (p->var != q->var) throw exc::engine_error("variable index is not consistent");
604 if (q->left->right != q) throw exc::engine_error("the double link list is inconsistent");
605 if (q->left != p and q->left->exp >= q->exp) throw exc::engine_error("exponents are not increasing going to the right");
606 }
607
608 // Now we continue
609 p = p->val.down;
610 if (p != nullptr)
611 p = p->right;
612 }
613 else if (p->tag == Nmi_node::leaf)
614 {
615 p = p->right;
616 }
617 }
618
619 return true;
620}
621
623// Insert the monomial (and baggage) 'm', if it
624// is not already in the monomial ideal. Return whether the
625// monomial was actually inserted.
626{
627 Bag *old_b;
628 const_varpower m = b->monom().data();
629
630 if (search(m, old_b))
631 {
632 delete b;
633 return 0;
634 }
636 return 1;
637}
638
640{
642 assert(P != nullptr);
643 const Monoid *M = P->getMonoid();
644 if (size() == 0)
645 {
646 o << "0";
647 return;
648 }
649 if (is_one())
650 {
651 if (size() != 1)
652 std::cout << "bad news: count is not 1, but ideal is 1..." << std::endl;
653 o << "1";
654 return;
655 }
656 monomial m = M->make_one();
657 for (Bag& j : *this)
658 {
659 const_varpower n = j.monom().data();
660 M->from_varpower(n, m);
661 M->elem_text_out(o, m);
662 if (M2_gbTrace > 0) o << '(' << j.basis_elem() << ")";
663 o << ' ';
664 }
665 M->remove(m);
666}
667
669{
670 // The idea: take the elements of 'this'
671 // for each: if the element is in J, then keep it directly.
672 // otherwie compute the lcm's.
673 VECTOR(Bag*) new_elems;
674 for (Bag& a : *this)
675 {
676 Bag *c;
677 if (J.search(a.monom().data(), c))
678 {
679 new_elems.push_back(new Bag(a));
680 }
681 else
682 for (Bag& b : J)
683 {
684 Bag *new_elem = new Bag(a.basis_elem());
685 varpower::lcm(a.monom().data(),
686 b.monom().data(),
687 new_elem->monom());
688 new_elems.push_back(new_elem);
689 }
690 }
691 MonomialIdeal *result = new MonomialIdeal(get_ring(), new_elems);
692 GC_reachable_here(&J);
693 return result;
694}
695
697// Compute (this : m), where m is a varpower monomial.
698{
699 VECTOR(Bag*) new_elems;
700 for (Bag& a : *this)
701 {
702 Bag *b = new Bag(a.basis_elem());
703 varpower::lcm(a.monom().data(), m, b->monom());
704 new_elems.push_back(b);
705 }
706 MonomialIdeal *result = new MonomialIdeal(get_ring(), new_elems);
707 return result;
708}
709
711{
712 VECTOR(Bag*) new_elems;
713 for (Bag& a : *this)
714 for (Bag& b : J)
715 {
716 Bag *c = new Bag(a.basis_elem());
717 varpower::mult(a.monom().data(), b.monom().data(), c->monom());
718 new_elems.push_back(c);
719 }
720
721 MonomialIdeal *result = new MonomialIdeal(get_ring(), new_elems);
722 GC_reachable_here(&J);
723 return result;
724}
725
727{
728 VECTOR(Bag*) new_elems;
729 for (Bag& a : *this)
730 {
731 new_elems.push_back(new Bag(a));
732 }
733 for (Bag& a : J)
734 {
735 new_elems.push_back(new Bag(a));
736 }
737 MonomialIdeal *result = new MonomialIdeal(get_ring(), new_elems);
738 GC_reachable_here(&J);
739 return result;
740}
741
743// Create the monomial ideal consisting of those elements of 'this'
744// that are not in 'J'. The baggage is left the same.
745{
747 for (Bag& a : *this)
748 {
749 Bag *c;
750 if (!J.search(a.monom().data(), c))
751 {
752 result->insert_minimal(new Bag(a));
753 }
754 }
755 GC_reachable_here(&J);
756 return result;
757}
758
760// Compute (this : m), where m is a varpower monomial.
761{
762 VECTOR(Bag*) new_elems;
763 for (Bag& a : *this)
764 {
765 Bag *b = new Bag(a.basis_elem());
766 varpower::quotient(a.monom().data(), m, b->monom());
767 new_elems.push_back(b);
768 }
769 MonomialIdeal *result = new MonomialIdeal(get_ring(), new_elems);
770 return result;
771}
772
774{
775 // std::cout << "--calling quotient -- I = ";
776 // dmonideal(const_cast<MonomialIdeal*>(this));
777 // std::cout << std::endl << " -- J = ";
778 // dmonideal(const_cast<MonomialIdeal*>(&J));
779 // std::cout << std::endl << " -- I:J = ";
780 // debug_check();
781 // J.debug_check();
782
784 Bag *b = new Bag();
785 varpower::one(b->monom());
786 result->insert(b);
787 for (Bag& a : J)
788 {
789 MonomialIdeal *result1 = quotient(a.monom().data());
790 // result1->debug_check();
791 MonomialIdeal *next_result = result->intersect(*result1);
792 // next_result->debug_check();
793 delete result1;
794 delete result;
795 result = next_result;
796 }
797 // dmonideal(result);
798 // std::cout << "----" << std::endl;
799 GC_reachable_here(&J);
800 return result;
801}
802
804 const M2_arrayint top,
806{
807 // If m is a varpower monomial, xi1^a1 ... xin^an, create the monomial ideal
808 // (xi1^(top[i1]+1-a1), ..., xin^(top[in]+1-an))
810 for (index_varpower i = vp; i.valid(); ++i)
811 {
812 Bag *b = new Bag();
814 i.var(), top->array[i.var()] + 1 - i.exponent(), b->monom());
815 result->insert(b);
816 }
817 return result;
818}
820// Returns the lcm of all of the generators of this, as an array of ints
821{
823 for (int i = 0; i < result->len; i++) result->array[i] = 0;
824
825 for (Bag& a : *this)
826 {
827 for (index_varpower j = a.monom().data(); j.valid(); ++j)
828 if (result->array[j.var()] < j.exponent())
829 result->array[j.var()] = j.exponent();
830 }
831 return result;
832}
833
835// a is a vector which is entrywise >= lcm(this).
836{
838 Bag *b = new Bag();
839 varpower::one(b->monom());
840 result->insert(b);
841 for (Bag& b : *this)
842 {
843 MonomialIdeal *I1 =
844 varpower_monideal(get_ring(), a, b.monom().data());
845 MonomialIdeal *next_result = result->intersect(*I1);
846 delete I1;
847 delete result;
848 result = next_result;
849 }
850 return result;
851}
852
854{
855 debug_check();
856 VECTOR(Bag*) new_elems;
857 for (Bag& a : *this)
858 {
859 Bag *b = new Bag(a.basis_elem());
860 varpower::erase(a.monom().data(), m, b->monom());
861 new_elems.push_back(b);
862 }
863 MonomialIdeal *result = new MonomialIdeal(get_ring(), new_elems);
864 result->debug_check();
865 return result;
866}
867
868
870{
871 // std::cout << "--calling sat -- I = ";
872 // dmonideal(const_cast<MonomialIdeal*>(this));
873 // std::cout << std::endl << " -- J = ";
874 // dmonideal(const_cast<MonomialIdeal*>(&J));
875 // std::cout << std::endl << " -- sat(I,J) = ";
876 // debug_check();
877 // J.debug_check();
878
880 Bag *b = new Bag();
881 varpower::one(b->monom());
882 result->insert(b);
883 for (Bag& a : J)
884 {
885 MonomialIdeal *result1 = erase(a.monom().data());
886 // result1->debug_check();
887 MonomialIdeal *next_result = result->intersect(*result1);
888 // next_result->debug_check();
889 delete result1;
890 delete result;
891 result = next_result;
892 }
893 // dmonideal(result);
894 // std::cout << "----" << std::endl;
895 GC_reachable_here(&J);
896 return result;
897}
898
900{
901 // std::cout << "monideal: calling radical on ";
902 // dmonideal(const_cast<MonomialIdeal*>(this));
903 // std::cout << std::endl << " -- radical(I) = ";
904
905 VECTOR(Bag*) new_elems;
906 for (Bag& a : *this)
907 {
908 Bag *b = new Bag(a.basis_elem());
909 varpower::radical(a.monom().data(), b->monom());
910 new_elems.push_back(b);
911 }
912 MonomialIdeal *result = new MonomialIdeal(get_ring(), new_elems);
913 // dmonideal(result);
914 // std::cout << "----" << std::endl;
915 return result;
916}
917
918static void borel1(VECTOR(Bag *) &result, exponents_t m, int loc, int nvars)
919{
920 if (loc == 0)
921 {
922 Bag *b = new Bag();
923 varpower::from_expvector(nvars, m, b->monom());
924 result.push_back(b);
925 }
926 else
927 {
928 int a = m[loc];
929 for (int i = 0; i <= a; i++)
930 {
931 borel1(result, m, loc - 1, nvars);
932 m[loc]--;
933 m[loc - 1]++;
934 }
935 m[loc] += a + 1;
936 m[loc - 1] -= a + 1;
937 }
938}
939
941// Return the smallest borel monomial ideal containing 'this'.
942{
943 VECTOR(Bag *) new_elems;
944 exponents_t bexp = newarray_atomic(int, get_ring()->n_vars());
945 for (Bag& b : *this)
946 {
947 varpower::to_expvector(get_ring()->n_vars(), b.monom().data(), bexp);
948 borel1(new_elems, bexp, get_ring()->n_vars() - 1, get_ring()->n_vars());
949 }
950 MonomialIdeal *result = new MonomialIdeal(get_ring(), new_elems);
951 freemem(bexp);
952 return result;
953}
954
956{
957 exponents_t bexp = newarray_atomic(int, get_ring()->n_vars());
958 for (Bag& b : *this)
959 {
960 Bag *c;
961 varpower::to_expvector(get_ring()->n_vars(), b.monom().data(), bexp);
962 for (int j = get_ring()->n_vars() - 1; j >= 1; j--)
963 if (bexp[j] > 0)
964 {
965 bexp[j]--;
966 bexp[j - 1]++;
967 int isthere = search_expvector(bexp, c);
968 bexp[j]++;
969 bexp[j - 1]--;
970 if (!isthere) return 0;
971 }
972 }
973 freemem(bexp);
974 return 1;
975}
976
978{
979 if (size() != 1) return false;
980 Nmi_node *p = mi->left;
981 if (p->var != 0 || p->exp != 0 || p->tag != Nmi_node::leaf) return false;
982 return true;
983}
984
986// Is each variable to some power in the monideal?
987{
988 int npure = 0;
989 int v, e;
990 for (Bag& b : *this)
991 {
992 const_varpower m = b.monom().data();
993 if (varpower::is_pure_power(m, v, e)) npure++;
994 }
995 return npure;
996}
997
998// Local Variables:
999// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
1000// indent-tabs-mode: nil
1001// End:
varpower::ConstExponents const_varpower
ExponentListIterator< int, true > index_varpower
Variable-length sparse (variable, exponent) encoding of monomials.
exponents::ConstExponents const_exponents
exponents::Exponents exponents_t
Dense exponent-vector template [e_0, ..., e_{nvars-1}] for monomial operations.
static void radical(ConstExponents a, Vector &result)
static HashExponent computeHashValue(ConstExponents vp)
static void one(Vector &result)
static void lcm(ConstExponents a, ConstExponents b, Vector &result)
static void mult(ConstExponents a, ConstExponents b, Vector &result)
static void quotient(ConstExponents a, ConstExponents b, Vector &result)
static void from_expvector(int n, exponents::ConstExponents a, Vector &result)
static Exponent simple_degree(ConstExponents m)
static void elem_text_out(buffer &o, ConstExponents m, bool p_one=true)
static void erase(ConstExponents a, ConstExponents b, Vector &result)
static bool is_pure_power(ConstExponents a, Exponent &v, Exponent &e)
static bool is_equal(ConstExponents a, ConstExponents b)
static void to_expvector(int n, ConstExponents a, exponents::Exponents result)
static void var(Exponent v, Exponent e, Vector &result)
void elem_text_out(buffer &o, const_monomial m, bool p_one=true) const
Definition monoid.cpp:575
void from_varpower(const_varpower vp, monomial result) const
Definition monoid.cpp:728
monomial make_one() const
Definition monoid.cpp:455
void remove(monomial d) const
Definition monoid.cpp:462
Engine-side commutative monomial monoid: variable names, ordering, multidegree machinery,...
Definition monoid.hpp:89
Bidirectional forward iterator over the Bags stored in a MonomialIdeal.
Definition monideal.hpp:230
int search(const_varpower m, Bag *&b) const
Definition monideal.cpp:278
Nmi_node * next(Nmi_node *p) const
Definition monideal.cpp:285
void do_node(Nmi_node *p, int indent, int disp) const
Definition monideal.cpp:465
int insert(Bag *b)
Definition monideal.cpp:622
virtual unsigned int computeHashValue() const
Definition monideal.cpp:28
MonomialIdeal * erase(const_varpower m) const
Definition monideal.cpp:853
int search_expvector(const_exponents m, Bag *&b) const
Definition monideal.cpp:214
int remove(Bag *&b)
Definition monideal.cpp:451
void insert_minimal(Bag *b)
Definition monideal.hpp:333
M2_arrayint lcm() const
Definition monideal.cpp:819
bool is_equal(const MonomialIdeal &mi) const
Definition monideal.cpp:195
MonomialIdeal * operator+(const MonomialIdeal &F) const
Definition monideal.cpp:726
void debug_out(int disp=1) const
Definition monideal.cpp:508
int n_pure_powers() const
Definition monideal.cpp:985
Nmi_node * new_leaf_mi_node(int v, int e, Bag *b)
Definition monideal.cpp:62
MonomialIdeal * quotient(const_varpower m) const
Definition monideal.cpp:759
int debug_check(Nmi_node *p, const Nmi_node *up) const
Definition monideal.cpp:524
const PolynomialRing * R
Definition monideal.hpp:137
void delete_mi_node(Nmi_node *p)
Definition monideal.cpp:78
bool is_borel() const
Definition monideal.cpp:955
MonomialIdeal(const PolynomialRing *RR, stash *mi_stash=nullptr)
Definition monideal.cpp:91
MonomialIdeal * sat(const MonomialIdeal &J) const
Definition monideal.cpp:869
MonomialIdeal * operator*(const MonomialIdeal &G) const
Definition monideal.cpp:710
void find_all_divisors(const_exponents exp, VECTOR(Bag *)&b) const
Definition monideal.cpp:246
void text_out(buffer &o) const
Definition monideal.cpp:639
Nmi_node * first_node() const
Definition monideal.hpp:339
int size() const
Definition monideal.hpp:186
MonomialIdeal * copy() const
Definition monideal.cpp:187
void remove_MonomialIdeal()
Definition monideal.cpp:43
void do_tree(Nmi_node *p, int depth, int indent, int disp) const
Definition monideal.cpp:494
Nmi_node * mi
Definition monideal.hpp:138
void insert1(Nmi_node *&p, Bag *b)
Definition monideal.cpp:321
stash * mi_stash
Definition monideal.hpp:142
MonomialIdeal * intersect(const_varpower m) const
Definition monideal.cpp:696
bool is_one() const
Definition monideal.cpp:977
bool isWellFormed() const
Definition monideal.cpp:578
MonomialIdeal * operator-(const MonomialIdeal &F) const
Definition monideal.cpp:742
MonomialIdeal * borel() const
Definition monideal.cpp:940
Iterator end() const
Definition monideal.hpp:279
void debug_check() const
Definition monideal.cpp:567
const_varpower second_elem() const
Definition monideal.cpp:182
Nmi_node * new_internal_mi_node(int v, int e, Nmi_node *d)
Definition monideal.cpp:49
MonomialIdeal * alexander_dual(const M2_arrayint a) const
Definition monideal.cpp:834
const PolynomialRing * get_ring() const
Definition monideal.hpp:190
MonomialIdeal * radical() const
Definition monideal.cpp:899
Nmi_node * prev(Nmi_node *p) const
Definition monideal.cpp:303
void remove1(Nmi_node *p)
Definition monideal.cpp:397
Iterator begin() const
Definition monideal.hpp:277
const_varpower first_elem() const
Definition monideal.cpp:177
Engine-side monomial ideal: a decision tree of Nmi_nodes storing the (typically minimal) generators b...
Definition monideal.hpp:136
Bag *& baggage()
Definition monideal.hpp:103
enum Nmi_node::@355074146072071371146336002330246050056154227161 tag
gc_vector< int > & monom()
Definition monideal.hpp:104
Nmi_node * header
Definition monideal.hpp:84
void insert_to_left(Nmi_node *q)
Definition monideal.hpp:106
Nmi_node * down
Definition monideal.hpp:88
Nmi_node * left
Definition monideal.hpp:82
Nmi_node * right
Definition monideal.hpp:83
Internal tree node of the MonomialIdeal decision tree.
Definition monideal.hpp:74
virtual const Monoid * getMonoid() const
Definition polyring.hpp:282
virtual const PolynomialRing * cast_to_PolynomialRing() const
Definition polyring.hpp:304
Abstract base for the engine's polynomial-ring hierarchy.
Definition polyring.hpp:96
char * str()
Definition buffer.hpp:72
int basis_elem() const
Definition int-bag.hpp:66
gc_vector< int > & monom()
Definition int-bag.hpp:60
Definition mem.hpp:78
Debugger-callable d* helpers that pretty-print engine values to stderr.
static int ndepth
static int nnodes
static int nleaves
static int nlists
#define monomial
Definition gb-toric.cpp:11
int p
int_bag Bag
Definition int-bag.hpp:70
void freemem(void *s)
Definition m2-mem.cpp:103
VALGRIND_MAKE_MEM_DEFINED & result(result)
M2_arrayint M2_makearrayint(int n)
Definition m2-types.cpp:6
char newline[]
Definition m2-types.cpp:49
int M2_gbTrace
Definition m2-types.cpp:52
static void borel1(VECTOR(Bag *) &result, exponents_t m, int loc, int nvars)
Definition monideal.cpp:918
static MonomialIdeal * varpower_monideal(const PolynomialRing *R, const M2_arrayint top, const_varpower vp)
Definition monideal.cpp:803
MonomialIdeal — exponent-vector-only representation of an ideal generated by monomials.
Monoid — variable count, naming, grading, and monomial order of a polynomial ring.
#define VECTOR(T)
Definition newdelete.hpp:78
#define newarray_atomic(T, len)
Definition newdelete.hpp:91
#define ARRAY_ON_STACK(type, nelems)
ARRAY_ON_STACK.
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.