Macaulay2 Engine
Loading...
Searching...
No Matches
res-f4-monlookup.cpp
Go to the documentation of this file.
1// Copyright 1994-2016 Michael E. Stillman
2
4
5#include "buffer.hpp" // for buffer
6#include "interface/m2-types.h" // for newline
7#include "mem.hpp" // for stash
8#include "schreyer-resolution/res-monomial-types.hpp" // for index_res_v...
9#include "style.hpp" // for INTSIZE
10#include "text-io.hpp" // for emit, emit_...
11
12#include <cassert> // for assert
13#include <cstddef> // for NULL
14#include <stdint.h> // for int32_t
15#include <vector> // for vector, vec...
16
17template <typename Key>
21 mi_node *d)
22{
23 mi_node *p = reinterpret_cast<mi_node *>(mi_stash->new_elem());
24 p->var = v;
25 p->exp = e;
26 p->left = nullptr;
27 p->right = nullptr;
28 p->header = nullptr;
29 p->tag = mi_node::node;
30 p->val.down = d;
31 return p;
32}
33
34template <typename Key>
38 Key k)
39{
40 mi_node *p = reinterpret_cast<mi_node *>(mi_stash->new_elem());
41 p->var = v;
42 p->exp = e;
43 p->left = nullptr;
44 p->right = nullptr;
45 p->header = nullptr;
46 p->tag = mi_node::leaf;
47 p->val.key = k;
48 return p;
49}
50
51template <typename Key>
53{
54 if (p == nullptr) return;
55 if (p->right != p->header) delete_mi_node(p->right);
56 if (p->tag == mi_node::node)
57 {
58 if (p->header != p) delete_mi_node(p->down());
59 }
60 mi_stash->delete_elem(p);
61}
62
63template <typename Key>
65 stash *mi_stash0)
66{
67 count = 0;
68 mi_stash = mi_stash0;
69 if (mi_stash == nullptr)
70 {
71 count = 1;
72 mi_stash = new stash("mi_node", sizeof(mi_node));
73 }
74
75 size_of_exp = nvars;
77}
78
79template <typename Key>
81{
82 for (typename VECTOR(mi_node *)::const_iterator i = mis.begin();
83 i != mis.end();
84 i++)
86 if ((count % 2) == 1) delete mi_stash;
87}
88
89template <typename Key>
92 Key k)
93{
94 count += 2;
95 mi_node **p = &top, *up = nullptr;
96 bool one_element = true;
97
98 for (index_res_varpower_monomial i = b; i.valid();)
99 {
100 one_element = false;
101 varpower_word insert_var = i.var();
102 varpower_word insert_exp;
103
104 if (*p == nullptr)
105 {
106 // make a new header node
107 *p = new_mi_node(insert_var, 0, up);
108 (*p)->header = (*p)->left = (*p)->right = *p;
109 }
110 else if ((*p)->var < insert_var)
111 {
112 // make a new layer
113 mi_node *header_node, *zero_node;
114 header_node = new_mi_node(insert_var, 0, up);
115 zero_node = new_mi_node(insert_var, 0, *p);
116
117 header_node->left = header_node->right = zero_node;
118 (*p)->down() = zero_node;
119 *p = header_node->header = zero_node->header = zero_node->left =
120 zero_node->right = header_node;
121 }
122
123 if ((*p)->var > insert_var)
124 {
125 insert_var = (*p)->var;
126 insert_exp = 0;
127 }
128 else
129 {
130 insert_exp = i.exponent();
131 ++i;
132 }
133
134 mi_node *q = (*p)->right;
135 while ((q != q->header) && (q->exp < insert_exp)) q = q->right;
136 if (q->exp != insert_exp)
137 {
138 mi_node *insert_node;
139
140 if (i.valid())
141 {
142 insert_node = new_mi_node(
143 insert_var, insert_exp, static_cast<mi_node *>(nullptr));
144 q->insert_to_left(insert_node);
145 q = insert_node;
146 }
147 else
148 {
149 insert_node = new_mi_node(insert_var, insert_exp, k);
150 q->insert_to_left(insert_node);
151 return;
152 }
153 }
154
155 up = q;
156 p = &(q->down());
157 }
158 if (one_element)
159 {
160 // insert a header node and a var/exp = 0/0 leaf
161 top = new_mi_node(0, 0, static_cast<mi_node *>(nullptr));
162 mi_node *leaf_node = new_mi_node(0, 0, k);
163 top->left = top->right = leaf_node;
164 top->header = leaf_node->header = leaf_node->left = leaf_node->right =
165 top;
166 }
167}
168
169template <typename Key>
171 mi_node *mi,
173 Key &result_k) const
174// mi is the top: where to start looking
175{
176 if (mi == nullptr) return false;
177
178 mi_node *p = mi;
179
180 for (;;)
181 {
182 p = p->right;
183
184 if (p == p->header)
185 {
186 if ((p = p->down()) == nullptr) return false;
187 continue;
188 }
189
190 if (p->exp > exp[p->var])
191 {
192 if ((p = p->header->down()) == nullptr) return false;
193 continue;
194 }
195
196 if (p->tag == mi_node::leaf)
197 {
198 result_k = p->key();
199 return true;
200 }
201
202 p = p->down();
203 }
204}
205
206template <typename Key>
208 mi_node *mi,
210 VECTOR(Key) & result_k) const
211{
212 mi_node *p = mi;
213
214 for (;;)
215 {
216 p = p->right;
217
218 if (p == p->header)
219 {
220 if ((p = p->down()) == nullptr) return;
221 continue;
222 }
223
224 if (p->exp > exp[p->var])
225 {
226 if ((p = p->header->down()) == nullptr) return;
227 continue;
228 }
229
230 if (p->tag == mi_node::leaf)
231 {
232 result_k.push_back(p->key());
233 }
234 else
235 p = p->down();
236 }
237}
238
239template <typename Key>
241 int topvar,
243{
244 int nvars = topvar + 1;
245 if (*m > 0 && m[1] >= nvars) nvars = static_cast<int>(m[1] + 1);
246 if (size_of_exp <= nvars)
247 {
248 // Increase size of exponent vector
249 freemem(exp0);
250 if (nvars > 2 * size_of_exp)
251 size_of_exp = nvars;
252 else
253 size_of_exp *= 2;
254
256 }
257
258 int nparts = static_cast<int>(*m++);
259 for (int i = nparts; i > 0; i--, m += 2)
260 {
261 exp0[*m] = m[1];
262 }
263}
264
265template <typename Key>
268{
269 int nparts = static_cast<int>(*m++);
270 for (int i = nparts; i > 0; i--, m += 2)
271 {
272 exp0[*m] = 0;
273 }
274}
275
276template <typename Key>
278 long comp,
280 Key &result_k) const
281{
282 if (comp >= mis.size()) return false;
283 mi_node *mi = mis[comp];
284 if (mi == nullptr) return false;
285
287 me->update_expvector(static_cast<int>(mi->var), m);
288 bool result = find_one_divisor1(mi, exp0, result_k);
289 me->reset_expvector(m);
290 return result;
291}
292
293template <typename Key>
295 long comp,
297 VECTOR(Key) & result_k) const
298{
299 if (comp >= mis.size()) return;
300 mi_node *mi = mis[comp];
301 if (mi == nullptr) return;
302
304 me->update_expvector(static_cast<int>(mi->var), m);
305 find_all_divisors1(mi, exp0, result_k);
306 me->reset_expvector(m);
307}
308
309template <typename Key>
311 const ResMonoid *M,
313 Key &result_k) const
314// mi is the top: where to start looking
315{
316 auto comp = M->get_component(m);
317 if (comp >= mis.size()) return false;
318 mi_node *mi = mis[comp];
319 if (mi == nullptr) return false;
320 M->to_expvector(m, exp0, comp);
321 return find_one_divisor1(mi, exp0, result_k);
322}
323
324template <typename Key>
326 const ResMonoid *M,
328 VECTOR(Key) & result_k) const
329{
330 auto comp = M->get_component(m);
331 if (comp >= mis.size()) return;
332 mi_node *mi = mis[comp];
333 if (mi == nullptr) return;
334 M->to_expvector(m, exp0, comp);
335 find_all_divisors1(mi, exp0, result_k);
336}
337
338template <typename Key>
340 long comp,
342 Key k)
343{
344 if (comp >= mis.size())
345 {
346 for (long j = comp - mis.size(); j >= 0; j--) mis.push_back(nullptr);
347 }
348 insert1(mis[comp], m, k);
349}
350
351template <typename Key>
354 Key &k)
355// Insert the monomial 'm' with key 'k', if it
356// is not already in the monomial ideal. Return whether the
357// monomial was actually inserted.
358{
359 if (find_one_divisor_vp(comp, m, k)) return false;
360 insert_minimal_vp(comp, m, k);
361 return true;
362}
363
364template <typename Key>
367{
368 while (p != nullptr)
369 {
370 p = p->left;
371 if (p->tag == mi_node::leaf)
372 return p;
373 else
374 p = p->down();
375 }
376 return nullptr;
377}
378
379template <typename Key>
382{
383 while (p != nullptr)
384 {
385 p = p->right;
386 if (p->tag == mi_node::leaf)
387 return p;
388 else
389 p = p->down();
390 }
391 return nullptr;
392}
393
394static int nlists = 0;
395static int nleaves = 0;
396static int nnodes = 0;
397static int ndepth = 0;
398
399template <typename Key>
401 int indent,
402 int disp) const
403{
404 buffer o;
405 int i;
406 assert(p->left != NULL);
407 assert(p->right != NULL);
408 assert(p->left->right == p);
409 assert(p->right->left == p);
410 if (disp)
411 {
412 for (i = 1; i <= indent; i++) o << ' ';
413 o << p->var << ' ' << p->exp;
414 }
415 if (p->tag == mi_node::leaf)
416 {
417 nleaves++;
418 if (disp) o << ' ' << p->key();
419 }
420 else if (p == p->header)
421 nlists++;
422 else
423 nnodes++;
424 emit_line(o.str());
425}
426
427template <typename Key>
429 int depth,
430 int indent,
431 int disp) const
432{
433 if (depth > ndepth) ndepth = depth;
434 do_node(p, indent, disp);
435 mi_node *q = p->right;
436 while (q != p)
437 {
438 do_node(q, indent, disp);
439 if (q->tag != mi_node::leaf)
440 do_tree(q->down(), depth + 1, indent + 2, disp);
441 q = q->right;
442 }
443}
444
445template <typename Key>
447// Display ResF4MonomialLookupTableT in tree-like form, collect statistics
448{
449 nlists = 0;
450 nnodes = 0;
451 nleaves = 0;
452 ndepth = 0;
453 for (typename VECTOR(mi_node *)::const_iterator i = mis.begin();
454 i != mis.end();
455 i++)
456 if (*i != NULL) do_tree(*i, 0, 0, disp);
457 buffer o;
458 o << "list nodes = " << nlists << newline;
459 o << "internal nodes = " << nnodes << newline;
460 o << "monomials = " << nleaves << newline;
461 o << "max depth = " << ndepth << newline;
462 emit(o.str());
463}
464
465template <typename Key>
467 const mi_node *const up) const
468// Returns the number of leaves at tree with root p.
469// Make sure that the list header is constructed ok, that the
470// left/right pointers are ok on this level, that the
471// var, exp, values in this train are correct.
472// Then loop through, checking each node (recursively) and each leaf
473{
474 mi_node *q;
475 // First check the node 'p' itself
476 assert(p != NULL);
477 assert(p->var >= 0);
478 if (up != nullptr) assert(p->var < up->var);
479 assert(p->header == p);
480 assert(p->tag == mi_node::node);
481 assert(p->down() == up);
482 assert(p->left != NULL);
483 assert(p->right != NULL);
484
485 // Now loop through each element in left/right chain, checking that
486 // v, e, left, right values are consistent.
487 for (q = p->left; q != p; q = q->left)
488 {
489 assert(q->left != NULL);
490 assert(q->right != NULL);
491 assert(q->header == p);
492 assert(q->right->left == q);
493 assert(q->left->right == q);
494 assert(q->var == p->var);
495 assert((q->right == p) || (q->exp < q->right->exp));
496 assert(q->exp >= 0);
497 }
498
499 // Now loop through again, this time descending into nodes
500 int c = 0;
501 for (q = p->right; q != p; q = q->right)
502 if (q->tag == mi_node::node)
503 c += debug_check(q->down(), q);
504 else
505 c++;
506 return c;
507}
508
509template <typename Key>
511{
512 int nfound = 0;
513 for (typename VECTOR(mi_node *)::const_iterator i = mis.begin();
514 i != mis.end();
515 i++)
516 {
517 if (*i != NULL) nfound += debug_check(*i, nullptr);
518 }
519 assert(count / 2 == nfound);
520}
521
522template <typename Key>
524{
525 o << "ResF4MonomialLookupTableT (";
526 o << count / 2 << " entries)\n";
527 int a = 0;
528 for (typename VECTOR(mi_node *)::const_iterator i = mis.begin();
529 i != mis.end();
530 i++)
531 {
532 for (mi_node *p = *i; p != nullptr; p = next(p))
533 {
534 if ((++a) % 15 == 0) o << newline;
535 o << p->key() << " ";
536 }
537 }
538}
539
541 elems,
542 VECTOR(int) & result_minimals,
543 stash *mi_stash)
544{
545 VECTOR(VECTOR(int) *) bins;
546 for (int j = 0; j < elems.size(); j++)
547 {
549 if (d >= bins.size())
550 for (int i = INTSIZE(bins); i <= d; i++) bins.push_back(nullptr);
551 if (bins[d] == nullptr) bins[d] = new VECTOR(int);
552 bins[d]->push_back(j);
553 }
554
555 // Now insert these into a lookup table
557 10, mi_stash); // The 10 is simply a suggested start value
558 for (int i = 0; i < bins.size(); i++)
559 if (bins[i] != nullptr)
560 {
561 for (VECTOR(int)::iterator j = bins[i]->begin(); j != bins[i]->end();
562 j++)
563 {
564 int k;
565 if (!M.find_one_divisor_vp(0, elems[*j], k))
566 {
567 M.insert_minimal_vp(0, elems[*j], 0);
568 result_minimals.push_back(*j);
569 }
570 }
571 freemem(bins[i]);
572 }
573}
574
576
577// Local Variables:
578// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
579// indent-tabs-mode: nil
580// End:
Append-only GC-backed byte buffer used throughout the engine for text output.
static Exponent simple_degree(ConstExponents m)
void insert_minimal_vp(long comp, const_varpower_monomial m, Key k)
res_const_ntuple_monomial const_ntuple_monomial
void do_node(mi_node *p, int indent, int disp) const
void debug_out(int disp=1) const
int debug_check(mi_node *p, const mi_node *up) const
void reset_expvector(const_varpower_monomial m)
void update_expvector(int topvar, const_varpower_monomial m)
void do_tree(mi_node *p, int depth, int indent, int disp) const
void text_out(buffer &o) const
mi_node * prev(mi_node *p) const
mi_node * next(mi_node *p) const
bool find_one_divisor_packed(const ResMonoid *M, const_packed_monomial m, Key &result_k) const
void find_all_divisors_vp(long comp, const_varpower_monomial m, VECTOR(Key) &result_k) const
res_const_packed_monomial const_packed_monomial
void find_all_divisors_packed(const ResMonoid *M, const_packed_monomial m, VECTOR(Key) &result_k) const
ResF4MonomialLookupTableT(int nvars, stash *mi_stash=nullptr)
bool insert_vp(long comp, const_varpower_monomial m, Key &k)
bool find_one_divisor1(mi_node *mi, const_ntuple_monomial exp, Key &result_k) const
res_const_varpower_monomial const_varpower_monomial
void find_all_divisors1(mi_node *mi, const_ntuple_monomial exp, VECTOR(Key) &result_k) const
bool find_one_divisor_vp(long comp, const_varpower_monomial m, Key &result_k) const
res_varpower_word varpower_word
mi_node * new_mi_node(varpower_word v, varpower_word e, mi_node *d)
void insert1(mi_node *&p, const_varpower_monomial m, Key k)
component_index get_component(res_const_packed_monomial m) const
bool to_expvector(res_const_packed_monomial m, res_ntuple_monomial result, component_index &result_comp) const
char * str()
Definition buffer.hpp:72
Definition mem.hpp:78
static int ndepth
static int nnodes
static int nleaves
static int nlists
int p
void freemem(void *s)
Definition m2-mem.cpp:103
VALGRIND_MAKE_MEM_DEFINED & result(result)
char newline[]
Definition m2-types.cpp:49
Engine-to-interpreter type vocabulary across the C++ / .dd boundary.
stash and doubling_stash — legacy size-class allocator interfaces, now stubbed to plain GC allocation...
#define newarray_atomic_clear(T, len)
Definition newdelete.hpp:93
#define VECTOR(T)
Definition newdelete.hpp:78
void minimalize_res_varpower_monomials(const VECTOR(res_varpower_monomial) &elems, VECTOR(int) &result_minimals, stash *mi_stash)
ResF4MonomialLookupTableT<Key> — tree-structured leading-term index for the F4 resolution.
ResMonoidDense ResMonoid
ExponentListIterator< myword, false > index_res_varpower_monomial
res_varpower_word * res_varpower_monomial
res_varpower_monomials::Exponent res_varpower_word
Typed-monomial vocabulary shared by ResMonoid, ResPolyRing, SchreyerFrame, and F4Res.
TermIterator< Nterm > begin(Nterm *ptr)
Definition ringelem.cpp:4
enum ResF4MonomialLookupTableT::mi_node::@025031101115250154050127052044034126032125025377 tag
#define INTSIZE(a)
Definition style.hpp:37
Engine-wide stylistic constants: LT / EQ / GT codes, INTSIZE, GEOHEAP_SIZE.
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.