Macaulay2 Engine
Loading...
Searching...
No Matches
f4-monlookup.cpp
Go to the documentation of this file.
1// (c) 1994-2021 Michael E. Stillman
2
3#include "f4/f4-monlookup.hpp"
4#include "buffer.hpp" // for buffer
5#include "interface/m2-types.h" // for newline
6#include "f4/varpower-monomial.hpp" // for varpower_word, const_varpower_mo...
7#include "text-io.hpp" // for emit, emit_line
8
9#include <cassert> // for assert
10#include <cstdint> // for int32_t
11#include <vector> // for vector, vector<>::iterator
12#include <algorithm>
13
14template <typename Key>
18 mi_node *d)
19{
20 mi_node *p = new mi_node;
21 p->var = v;
22 p->exp = e;
23 p->left = nullptr;
24 p->right = nullptr;
25 p->header = nullptr;
26 p->tag = mi_node::node;
27 p->val.down = d;
28 return p;
29}
30
31template <typename Key>
35 Key k)
36{
37 mi_node *p = new mi_node;
38 p->var = v;
39 p->exp = e;
40 p->left = nullptr;
41 p->right = nullptr;
42 p->header = nullptr;
43 p->tag = mi_node::leaf;
44 p->val.key = k;
45 return p;
46}
47
48template <typename Key>
50{
51 if (p == nullptr) return;
52 if (p->right != p->header) delete_mi_node(p->right);
53 if (p->tag == mi_node::node)
54 {
55 if (p->header != p) delete_mi_node(p->down());
56 }
57 delete p;
58}
59
60template <typename Key>
62{
63 count = 0;
64 size_of_exp = nvars;
66 std::fill(exp0, exp0 + size_of_exp, 0);
67}
68
69template <typename Key>
71{
72 for (auto& i : mis) delete_mi_node(i);
73 delete [] exp0;
74}
75
76template <typename Key>
79 Key k)
80{
81 count++;
82 mi_node **p = &top, *up = nullptr;
83 bool one_element = true;
84
85 for (index_varpower_monomial i = b; i.valid();)
86 {
87 one_element = false;
88 varpower_word insert_var = i.var();
89 varpower_word insert_exp;
90
91 if (*p == nullptr)
92 {
93 // make a new header node
94 *p = new_mi_node(insert_var, 0, up);
95 (*p)->header = (*p)->left = (*p)->right = *p;
96 }
97 else if ((*p)->var < insert_var)
98 {
99 // make a new layer
100 mi_node *header_node, *zero_node;
101 header_node = new_mi_node(insert_var, 0, up);
102 zero_node = new_mi_node(insert_var, 0, *p);
103
104 header_node->left = header_node->right = zero_node;
105 (*p)->down() = zero_node;
106 *p = header_node->header = zero_node->header = zero_node->left =
107 zero_node->right = header_node;
108 }
109
110 if ((*p)->var > insert_var)
111 {
112 insert_var = (*p)->var;
113 insert_exp = 0;
114 }
115 else
116 {
117 insert_exp = i.exponent();
118 ++i;
119 }
120
121 mi_node *q = (*p)->right;
122 while ((q != q->header) && (q->exp < insert_exp)) q = q->right;
123 if (q->exp != insert_exp)
124 {
125 mi_node *insert_node;
126
127 if (i.valid())
128 {
129 insert_node = new_mi_node(
130 insert_var, insert_exp, static_cast<mi_node *>(nullptr));
131 q->insert_to_left(insert_node);
132 q = insert_node;
133 }
134 else
135 {
136 insert_node = new_mi_node(insert_var, insert_exp, k);
137 q->insert_to_left(insert_node);
138 return;
139 }
140 }
141
142 up = q;
143 p = &(q->down());
144 }
145 if (one_element)
146 {
147 // insert a header node and a var/exp = 0/0 leaf
148 top = new_mi_node(0, 0, static_cast<mi_node *>(nullptr));
149 mi_node *leaf_node = new_mi_node(0, 0, k);
150 top->left = top->right = leaf_node;
151 top->header = leaf_node->header = leaf_node->left = leaf_node->right =
152 top;
153 }
154}
155
156template <typename Key>
159 Key &result_k) const
160// mi is the top: where to start looking
161{
162 if (mi == nullptr) return false;
163
164 mi_node *p = mi;
165
166 for (;;)
167 {
168 p = p->right;
169
170 if (p == p->header)
171 {
172 if ((p = p->down()) == nullptr) return false;
173 continue;
174 }
175
176 if (p->exp > exp[p->var])
177 {
178 if ((p = p->header->down()) == nullptr) return false;
179 continue;
180 }
181
182 if (p->tag == mi_node::leaf)
183 {
184 result_k = p->key();
185 return true;
186 }
187
188 p = p->down();
189 }
190}
191
192template <typename Key>
195 std::vector<Key>& result_k
196 ) const
197{
198 mi_node *p = mi;
199
200 for (;;)
201 {
202 p = p->right;
203
204 if (p == p->header)
205 {
206 if ((p = p->down()) == nullptr) return;
207 continue;
208 }
209
210 if (p->exp > exp[p->var])
211 {
212 if ((p = p->header->down()) == nullptr) return;
213 continue;
214 }
215
216 if (p->tag == mi_node::leaf)
217 {
218 result_k.push_back(p->key());
219 }
220 else
221 p = p->down();
222 }
223}
224
225template <typename Key>
227 int topvar,
229{
230 int nvars = topvar + 1;
231 if (*m > 0 && m[1] >= nvars) nvars = static_cast<int>(m[1] + 1);
232 if (size_of_exp <= nvars)
233 {
234 // Increase size of exponent vector
235 delete [] exp0;
236 if (nvars > 2 * size_of_exp)
237 size_of_exp = nvars;
238 else
239 size_of_exp *= 2;
240
242 for (auto i=0; i<size_of_exp; ++i) exp0[i] = 0;
243 }
244
245 int nparts = static_cast<int>(*m++);
246 for (int i = nparts; i > 0; i--, m += 2)
247 {
248 exp0[*m] = m[1];
249 }
250}
251
252template <typename Key>
255{
256 int nparts = static_cast<int>(*m++);
257 for (int i = nparts; i > 0; i--, m += 2)
258 {
259 exp0[*m] = 0;
260 }
261}
262
263template <typename Key>
266 Key &result_k) const
267{
268 if (comp >= mis.size()) return false;
269 mi_node *mi = mis[comp];
270 if (mi == nullptr) return false;
271
272 F4MonomialLookupTableT *me = const_cast<F4MonomialLookupTableT *>(this);
273 me->update_expvector(static_cast<int>(mi->var), m);
274 bool result = find_one_divisor1(mi, exp0, result_k);
275 me->reset_expvector(m);
276 return result;
277}
278
279template <typename Key>
281 long comp,
283 std::vector<Key> & result_k) const
284{
285 if (comp >= mis.size()) return;
286 mi_node *mi = mis[comp];
287 if (mi == nullptr) return;
288
289 F4MonomialLookupTableT *me = const_cast<F4MonomialLookupTableT *>(this);
290 me->update_expvector(static_cast<int>(mi->var), m);
291 find_all_divisors1(mi, exp0, result_k);
292 me->reset_expvector(m);
293}
294
295template <typename Key>
297 const MonomialInfo *M,
299 Key &result_k) const
300// mi is the top: where to start looking
301{
302 long comp = M->get_component(m);
303 if (comp >= mis.size()) return false;
304 mi_node *mi = mis[comp];
305 if (mi == nullptr) return false;
306 M->to_expvector(m, exp0, comp);
307 return find_one_divisor1(mi, exp0, result_k);
308}
309
310template <typename Key>
312 const MonomialInfo *M,
314 std::vector<Key> & result_k) const
315{
316 long comp = M->get_component(m);
317 if (comp >= mis.size()) return;
318 mi_node *mi = mis[comp];
319 if (mi == nullptr) return;
320 M->to_expvector(m, exp0, comp);
321 find_all_divisors1(mi, exp0, result_k);
322}
323
324template <typename Key>
327 Key k)
328{
329 while (comp >= mis.size()) mis.push_back(nullptr);
330 // if (comp >= mis.size())
331 // {
332 // for (long j = comp - mis.size(); j >= 0; j--) mis.push_back(nullptr);
333 // }
334 insert1(mis[comp], m, k);
335}
336
337template <typename Key>
340 Key &k)
341// Insert the monomial 'm' with key 'k', if it
342// is not already in the monomial ideal. Return whether the
343// monomial was actually inserted.
344{
345 if (find_one_divisor_vp(comp, m, k)) return false;
346 insert_minimal_vp(comp, m, k);
347 return true;
348}
349
350template <typename Key>
353{
354 while (p != nullptr)
355 {
356 p = p->left;
357 if (p->tag == mi_node::leaf)
358 return p;
359 else
360 p = p->down();
361 }
362 return nullptr;
363}
364
365template <typename Key>
368{
369 while (p != nullptr)
370 {
371 p = p->right;
372 if (p->tag == mi_node::leaf)
373 return p;
374 else
375 p = p->down();
376 }
377 return nullptr;
378}
379
380static int nlists = 0;
381static int nleaves = 0;
382static int nnodes = 0;
383static int ndepth = 0;
384
385template <typename Key>
387 int indent,
388 int disp) const
389{
390 buffer o;
391 int i;
392 assert(p->left != nullptr);
393 assert(p->right != nullptr);
394 assert(p->left->right == p);
395 assert(p->right->left == p);
396 if (disp)
397 {
398 for (i = 1; i <= indent; i++) o << ' ';
399 o << p->var << ' ' << p->exp;
400 }
401 if (p->tag == mi_node::leaf)
402 {
403 nleaves++;
404 if (disp) o << ' ' << p->key();
405 }
406 else if (p == p->header)
407 nlists++;
408 else
409 nnodes++;
410 emit_line(o.str());
411}
412
413template <typename Key>
415 int depth,
416 int indent,
417 int disp) const
418{
419 if (depth > ndepth) ndepth = depth;
420 do_node(p, indent, disp);
421 mi_node *q = p->right;
422 while (q != p)
423 {
424 do_node(q, indent, disp);
425 if (q->tag != mi_node::leaf)
426 do_tree(q->down(), depth + 1, indent + 2, disp);
427 q = q->right;
428 }
429}
430
431template <typename Key>
433// Display F4MonomialLookupTableT in tree-like form, collect statistics
434{
435 nlists = 0;
436 nnodes = 0;
437 nleaves = 0;
438 ndepth = 0;
439 for (auto& i : mis)
440 if (i != nullptr) do_tree(i, 0, 0, disp);
441 buffer o;
442 o << "list nodes = " << nlists << newline;
443 o << "internal nodes = " << nnodes << newline;
444 o << "monomials = " << nleaves << newline;
445 o << "max depth = " << ndepth << newline;
446 emit(o.str());
447}
448
449template <typename Key>
451 const mi_node *const up) const
452// Returns the number of leaves at tree with root p.
453// Make sure that the list header is constructed ok, that the
454// left/right pointers are ok on this level, that the
455// var, exp, values in this train are correct.
456// Then loop through, checking each node (recursively) and each leaf
457{
458 mi_node *q;
459 // First check the node 'p' itself
460 assert(p != nullptr);
461 assert(p->var >= 0);
462 if (up != nullptr) assert(p->var < up->var);
463 assert(p->header == p);
464 assert(p->tag == mi_node::node);
465 assert(p->down() == up);
466 assert(p->left != nullptr);
467 assert(p->right != nullptr);
468
469 // Now loop through each element in left/right chain, checking that
470 // v, e, left, right values are consistent.
471 for (q = p->left; q != p; q = q->left)
472 {
473 assert(q->left != nullptr);
474 assert(q->right != nullptr);
475 assert(q->header == p);
476 assert(q->right->left == q);
477 assert(q->left->right == q);
478 assert(q->var == p->var);
479 assert((q->right == p) || (q->exp < q->right->exp));
480 assert(q->exp >= 0);
481 }
482
483 // Now loop through again, this time descending into nodes
484 int c = 0;
485 for (q = p->right; q != p; q = q->right)
486 if (q->tag == mi_node::node)
487 c += debug_check(q->down(), q);
488 else
489 c++;
490 return c;
491}
492
493template <typename Key>
495{
496 int nfound = 0;
497 for (auto& i : mis)
498 {
499 if (i != nullptr) nfound += debug_check(i, nullptr);
500 }
501 assert(count == nfound);
502}
503
504template <typename Key>
506{
507 o << "F4MonomialLookupTableT (";
508 o << count << " entries)\n";
509 int a = 0;
510 for (auto& i : mis)
511 {
512 for (mi_node *p = i; p != nullptr; p = next(p))
513 {
514 if ((++a) % 15 == 0) o << newline;
515 o << p->key() << " ";
516 }
517 }
518}
519
520void minimalize_varpower_monomials(const std::vector<varpower_monomial> & elems,
521 std::vector<int> & result_minimals)
522{
523 std::vector<std::pair<int, int>> degs_and_indices;
524 int count = 0;
525 for (auto& b : elems)
526 {
528 degs_and_indices.push_back(std::make_pair(deg, count));
529 ++count;
530 }
531 std::stable_sort(degs_and_indices.begin(), degs_and_indices.end());
532
533 F4MonomialLookupTableT<int> M(10); // 10 is simply a suggested value
534 for (auto p : degs_and_indices)
535 {
536 int k; // unused: we only care if there is a divisor, not which index it has
537 if (!M.find_one_divisor_vp(0, elems[p.second], k))
538 {
539 M.insert_minimal_vp(0, elems[p.second], 0);
540 result_minimals.push_back(p.second);
541 }
542 }
543}
544
546
547// Local Variables:
548// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
549// indent-tabs-mode: nil
550// End:
Append-only GC-backed byte buffer used throughout the engine for text output.
static Exponent simple_degree(ConstExponents m)
void reset_expvector(const_varpower_monomial m)
mi_node * next(mi_node *p) const
void update_expvector(int topvar, const_varpower_monomial m)
void text_out(buffer &o) const
bool find_one_divisor_packed(const MonomialInfo *M, const_packed_monomial m, Key &result_k) const
int debug_check(mi_node *p, const mi_node *up) const
void do_node(mi_node *p, int indent, int disp) const
bool insert_vp(long comp, const_varpower_monomial m, Key &k)
void do_tree(mi_node *p, int depth, int indent, int disp) const
bool find_one_divisor1(mi_node *mi, const_ntuple_monomial exp, Key &result_k) const
mi_node * new_mi_node(varpower_word v, varpower_word e, mi_node *d)
void debug_out(int disp=1) const
F4MonomialLookupTableT(int nvars)
void insert_minimal_vp(long comp, const_varpower_monomial m, Key k)
void find_all_divisors_vp(long comp, const_varpower_monomial m, std::vector< Key > &result_k) const
void delete_mi_node(mi_node *p)
std::vector< mi_node * > mis
mi_node * prev(mi_node *p) const
void find_all_divisors1(mi_node *mi, const_ntuple_monomial exp, std::vector< Key > &result_k) const
void find_all_divisors_packed(const MonomialInfo *M, const_packed_monomial m, std::vector< Key > &result_k) const
void insert1(mi_node *&p, const_varpower_monomial m, Key k)
bool find_one_divisor_vp(long comp, const_varpower_monomial m, Key &result_k) const
bool to_expvector(const_packed_monomial m, ntuple_monomial result, long &result_comp) const
Definition moninfo.hpp:246
long get_component(const_packed_monomial m) const
Definition moninfo.hpp:185
Per-ring monomial layout / encoding helper used by F4GB.
Definition moninfo.hpp:108
char * str()
Definition buffer.hpp:72
static int ndepth
static int nnodes
void minimalize_varpower_monomials(const std::vector< varpower_monomial > &elems, std::vector< int > &result_minimals)
static int nleaves
static int nlists
F4MonomialLookupTableT<Key> — monomial-ideal trie for divisor lookup.
int p
VALGRIND_MAKE_MEM_DEFINED & result(result)
char newline[]
Definition m2-types.cpp:49
Engine-to-interpreter type vocabulary across the C++ / .dd boundary.
const monomial_word * const_packed_monomial
Definition moninfo.hpp:79
ntuple_monomials::Exponent ntuple_word
const ntuple_word * const_ntuple_monomial
enum F4MonomialLookupTableT::mi_node::@106101245262356146223070047151024177106047314172 tag
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.
const varpower_word * const_varpower_monomial
varpower_monomials::Exponent varpower_word
ExponentListIterator< long, false > index_varpower_monomial
F4's (variable, exponent) sparse-monomial ExponentList specialisation (legacy).