Macaulay2 Engine
Loading...
Searching...
No Matches
f4.cpp
Go to the documentation of this file.
1// Copyright 2005-2021 Michael E. Stillman
2
3#include "f4/f4.hpp"
4#include "freemod.hpp" // for FreeModule
5#include "mat.hpp" // for MutableMatrix
6#include "text-io.hpp" // for emit
7#include "buffer.hpp" // for buffer
8#include "error.h" // for error
9#include "f4/f4-m2-interface.hpp" // for F4toM2Interface
10#include "f4/f4-spairs.hpp" // for F4SPairSet
11#include "f4/f4-types.hpp" // for row_elem, coefficient_matrix
12#include "f4/hilb-fcn.hpp" // for HilbertController
13#include "f4/memblock.hpp" // for F4MemoryBlock
14#include "f4/monhashtable.hpp" // for MonomialHashTable
15#include "f4/moninfo.hpp" // for MonomialInfo, monomial_word
16#include "f4/varpower-monomial.hpp" // for varpower_word, varpower_monomial
17#include "interface/mutable-matrix.h" // for IM2_MutableMatrix_make
18#include "interrupted.hpp" // for system_interrupted
19#include "ring.hpp" // for Ring
20#include "ringelem.hpp" // for ring_elem, vec
21#include "style.hpp" // for INTSIZE
22
23#include <gc/gc_allocator.h> // for gc_allocator
24#include <cstdint> // for int32_t
25#include <cstdio> // for fprintf, stderr
26#include <algorithm> // for stable_sort
27#include <vector> // for swap, vector
28#include <atomic> // for atomic ints in gauss_reduce
29#include <iostream>
30
31class RingElement;
32
34 const MonomialInfo *M0,
35 const FreeModule *F0,
36 M2_bool collect_syz,
37 int n_rows_to_keep,
38 M2_arrayint weights0,
39 int strategy,
40 M2_bool use_max_degree,
41 int max_degree,
42 int numThreads)
44 mMonomialInfo(M0),
45 mFreeModule(F0),
46 component_degrees(nullptr), // need to put this in
49 n_gens_left(0),
50 n_subring(0),
51 complete_thru_this_degree(-1), // need to reset this in the body
53 is_ideal(F0->rank() == 1),
54 hilbert(nullptr),
57 mLookupTable(mMonomialInfo->n_vars()),
59 mat(nullptr),
60 mMonomialHashTable(M0, 17),
62 next_monom(),
64 clock_gauss(0),
65 mGaussTime(0),
72#if defined(WITH_TBB)
73 mNumThreads(mtbb::numThreads(numThreads)),
74 mScheduler(mNumThreads),
76#else
78#endif
79{
80 (void) collect_syz;
81 (void) n_rows_to_keep;
82 (void) weights0;
83 (void) strategy;
84 (void) use_max_degree;
85 (void) max_degree;
86 // mLookupTable = new MonomialLookupTable(mMonomialInfo->n_vars());
87 // mSPairSet = new F4SPairSet(mMonomialInfo, mGroebnerBasis);
89
90 // TODO: set status?
91 if (M2_gbTrace >= 3) mMonomialInfo->show();
92}
93
95{
96 hilbert = new HilbertController(mFreeModule, hf); // TODO MES: GC problem?
97}
98
100{
101 for (auto g0 : g)
102 {
103 if (! g0->f.coeffs.isNull())
104 mVectorArithmetic->deallocateElementArray(g0->f.coeffs);
105 // Note: monomials will be cleared en-mass and so don't need to be freed.
106 delete g0;
107 }
108}
109
111{
112 // delete mSPairSet;
113 // delete mLookupTable;
114 delete mat;
115
116 // Now delete the gens, gb arrays.
119}
120
122 int &deg_result,
123 int &alpha) const
124{
125 const monomial_word *w = f.monoms;
126 monomial_word leaddeg = mMonomialInfo->monomial_heft(w);
127 monomial_word deg = leaddeg;
128
129 for (int i = 1; i < f.len; i++)
130 {
131 w = w + mMonomialInfo->monomial_size(w);
132 monomial_word degi = mMonomialInfo->monomial_heft(w);
133 if (degi > deg) deg = degi;
134 }
135 alpha = static_cast<int>(deg - leaddeg);
136 deg_result = static_cast<int>(deg);
137}
138
139void F4GB::new_generators(int lo, int hi)
140{
141 for (int i = lo; i <= hi; i++)
142 {
143 gbelem *g = mGenerators[i];
144 poly_set_degrees(g->f, g->deg, g->alpha);
145 if (g->f.len == 0) continue;
146 mSPairSet.insert_generator(g->deg, g->f.monoms, i);
147 }
148}
149
151// Creation of the matrix over K //////////////////
154{
155 // m is a packed monomial, unique via the hash table H, B.
156 column_elem c{};
157 int next_column = INTSIZE(mat->columns);
158 m[-1] = next_column;
159 c.monom = m;
160 c.head = -2;
161 mat->columns.push_back(c);
162 return next_column;
163}
164
166{
167 packed_monomial new_m;
168 if (mMonomialHashTable.find_or_insert(m, new_m)) return static_cast<int>(new_m[-1]);
169 // At this point, m is a new monomial to be placed as a column
170 m = next_monom;
171 mMonomialMemoryBlock.intern(1 + mMonomialInfo->monomial_size(m));
172 next_monom = mMonomialMemoryBlock.reserve(1 + mMonomialInfo->max_monomial_size());
173 next_monom++;
174 return new_column(m);
175}
176
178{
179 // We already have allocated space for a monomial
180 // Do the multiply
181 // Look it up in the hashtable
182 // If it is there, return its column
183 // If not, increment our memory block, and insert a new column.
184 packed_monomial new_m;
185 mMonomialInfo->unchecked_mult(m, n, next_monom);
186 if (mMonomialHashTable.find_or_insert(next_monom, new_m))
187 return static_cast<int>(
188 new_m[-1]); // monom exists, don't save monomial space
189 m = next_monom;
190 mMonomialMemoryBlock.intern(1 + mMonomialInfo->monomial_size(m));
191 next_monom = mMonomialMemoryBlock.reserve(1 + mMonomialInfo->max_monomial_size());
192 next_monom++;
193 return new_column(m);
194}
195
196void F4GB::load_gen(int which)
197{
198 GBF4Polynomial &g = mGenerators[which]->f;
199
200 row_elem r{};
201 r.monom = nullptr; // This says that this element corresponds to a generator
202 r.elem = which;
203 r.len = g.len;
204 // r.comps = Mem->components.allocate(g.len);
205 r.comps = new int[g.len];
206 // r.coeffs is already initialized to [nullptr].
207
208 // TODO: this iterator requires knowledge about memory layout of monomials
209 monomial_word *w = g.monoms;
210 for (int i = 0; i < g.len; i++)
211 {
212 mMonomialInfo->copy(w, next_monom);
214 w += mMonomialInfo->monomial_size(w);
215 }
216
217 mat->rows.push_back(r);
218}
219
220void F4GB::load_row(packed_monomial monom, int which)
221{
222 GBF4Polynomial &g = mGroebnerBasis[which]->f;
223
224 row_elem r{};
225 r.monom = monom;
226 r.elem = which;
227 r.len = g.len;
228 // r.comps = Mem->components.allocate(g.len);
229 r.comps = new int[g.len];
230 // r.coeffs is already initialized to [nullptr].
231
232 // TODO: this iterator requires knowledge about memory layout of monomials
233 monomial_word *w = g.monoms;
234 for (int i = 0; i < g.len; i++)
235 {
236 r.comps[i] = mult_monomials(monom, w);
237 w += mMonomialInfo->monomial_size(w);
238 }
239
240 mat->rows.push_back(r);
241}
242
244{
245 /* If this column has been handled before, return.
246 Otherwise, find a GB element whose lead term
247 divides this monomial, and either mark this column
248 as not an initial element, OR append a row
249 */
250
251 column_elem &ce = mat->columns[c];
252 if (ce.head >= -1) return;
253 int32_t which;
254 bool found = mLookupTable.find_one_divisor_packed(mMonomialInfo, ce.monom, which);
255 if (found)
256 {
258 mMonomialInfo->unchecked_divide(ce.monom, mGroebnerBasis[which]->f.monoms, n);
259 mMonomialMemoryBlock.intern(1 + mMonomialInfo->monomial_size(n));
260 next_monom = mMonomialMemoryBlock.reserve(1 + mMonomialInfo->max_monomial_size());
261 next_monom++;
262 // M->set_component(which, n);
263 ce.head = INTSIZE(mat->rows);
264 load_row(n, which);
265 }
266 else
267 ce.head = -1;
268}
269
271{
273 mMonomialInfo->unchecked_divide(p->lcm, mGroebnerBasis[p->i]->f.monoms, n);
274 mMonomialMemoryBlock.intern(1 + mMonomialInfo->monomial_size(n));
275 next_monom = mMonomialMemoryBlock.reserve(1 + mMonomialInfo->max_monomial_size());
276 next_monom++;
277 load_row(n, p->i);
278}
279
281{
283 mMonomialInfo->unchecked_divide(p->lcm, mGroebnerBasis[p->j]->f.monoms, n);
284 mMonomialMemoryBlock.intern(1 + mMonomialInfo->monomial_size(n));
285 next_monom = mMonomialMemoryBlock.reserve(1 + mMonomialInfo->max_monomial_size());
286 next_monom++;
287 load_row(n, p->j);
288}
289
291{
292 int c;
293
294 switch (p->type)
295 {
296 case SPairType::SPair:
297 {
299 c = mat->rows[mat->rows.size() - 1].comps[0];
300
301 if (mat->columns[c].head >= -1)
302 n_lcmdups++;
303 else
304 {
305 // In this situation, we load the other half as a reducer
307 mat->columns[c].head = INTSIZE(mat->rows) - 1;
308 }
309 break;
310 }
312 load_gen(p->i);
313 break;
315 break;
316 }
317}
318
319long ColumnsSorter::ncmps0 = 0;
320long ColumnsSorter::ncmps = 0;
321
323{
324 // Set up to sort the columns.
325 // Result is an array 0..ncols-1, giving the new order.
326 // Find the inverse of this permutation: place values into "ord" column
327 // fields.
328 // Loop through every element of the matrix, changing its comp array.
329
330 int nrows = INTSIZE(mat->rows);
331 int ncols = INTSIZE(mat->columns);
332
333 // sort the columns
334
335 int *column_order = new int[ncols];
336 int *ord = new int[ncols];
337
339
340// Actual sort of columns /////////////////
341
343
344 clock_t begin_time0 = clock();
345 for (int i = 0; i < ncols; i++)
346 {
347 column_order[i] = i;
348 }
349
350 if (M2_gbTrace >= 2) fprintf(stderr, "ncomparisons = ");
351
352 // std::cout << "-- before sort --" << std::endl;
353 // show_column_info();
354
355 std::stable_sort(column_order, column_order + ncols, C);
356
357 // std::cout << "-- after sort --" << std::endl;
358 // show_column_info();
359
360 clock_t end_time0 = clock();
361 if (M2_gbTrace >= 2) fprintf(stderr, "%ld, ", C.ncomparisons0());
362 double nsecs0 = (double)(end_time0 - begin_time0) / CLOCKS_PER_SEC;
363 clock_sort_columns += nsecs0;
364 if (M2_gbTrace >= 2) fprintf(stderr, " time = %f\n", nsecs0);
365
367
368 for (int i = 0; i < ncols; i++)
369 {
370 ord[column_order[i]] = i;
371 }
372
373 // Now move the columns into position
375 newcols.reserve(ncols);
376 for (int i = 0; i < ncols; i++)
377 {
378 long newc = column_order[i];
379 newcols.push_back(mat->columns[newc]);
380 }
381
382 // Now reset the components in each row
383 for (int r = 0; r < nrows; r++)
384 {
385 row_elem &row = mat->rows[r];
386 for (int i = 0; i < row.len; i++)
387 {
388 int oldcol = row.comps[i];
389 int newcol = ord[oldcol];
390 row.comps[i] = newcol;
391 }
392 for (int i = 1; i < row.len; i++)
393 {
394 if (row.comps[i] <= row.comps[i - 1])
395 {
396 fprintf(stderr, "Internal error: array out of order\n");
397 break;
398 }
399 }
400 }
401
402 std::swap(mat->columns, newcols);
403 delete [] column_order;
404 delete [] ord;
405 //Mem->components.deallocate(column_order);
406 //Mem->components.deallocate(ord);
407}
408
410{
411 int nrows = INTSIZE(mat->rows);
412 int ncols = INTSIZE(mat->columns);
414 std::vector<long> rowlocs; // 0..nrows-1 of where row as been placed
415
416 newrows.reserve(nrows);
417 rowlocs.reserve(nrows);
418 for (int r = 0; r < nrows; r++) rowlocs.push_back(-1);
419
420 for (int c = 0; c < ncols; c++)
421 {
422 int oldrow = mat->columns[c].head;
423 if (oldrow >= 0)
424 {
425 // Move the row into place
426 int newrow = INTSIZE(newrows);
427 newrows.push_back(mat->rows[oldrow]);
428 rowlocs[oldrow] = newrow;
429 mat->columns[c].head = newrow;
430 if (mat->columns[c].head == oldrow) mat->columns[c].head = newrow;
431 }
432 }
433 for (int r = 0; r < nrows; r++)
434 if (rowlocs[r] < 0) newrows.push_back(mat->rows[r]);
435 std::swap(mat->rows, newrows);
436}
437
439{
440 // mat
442 next_monom = mMonomialMemoryBlock.reserve(1 + mMonomialInfo->max_monomial_size());
443 next_monom++;
444}
445
447{
448 // Clear the rows first
449 for (auto & r : mat->rows)
450 {
451 // std::cout << "at A" << std::endl;
452 if (not r.coeffs.isNull())
453 mVectorArithmetic->deallocateElementArray(r.coeffs);
454 // Mem->components.deallocate(r.comps);
455 // std::cout << "at B" << std::endl;
456 if (r.comps != nullptr)
457 delete [] r.comps;
458 // std::cout << "at C" << std::endl;
459 r.len = 0;
460 r.elem = -1;
461 r.monom = nullptr;
462 }
463 mat->rows.clear();
464 mat->columns.clear();
465 mMonomialHashTable.reset();
466 mMonomialMemoryBlock.reset();
467}
468
470{
471 /* loop through all spairs, process,
472 then while there are any columns to process, do so,
473 then process rows.
474 Is this the best order to do it in? Maybe not...
475 */
476
477 //spair *p;
478 std::pair<bool,spair> p;
479 p = mSPairSet.get_next_pair();
480 while (p.first)
481 {
482 process_s_pair(&p.second);
483 p = mSPairSet.get_next_pair();
484 }
485
486 while (next_col_to_process < mat->columns.size())
488
489 // DEBUGGING:
490 if (M2_gbTrace >= 2)
491 {
492 fprintf(stderr,
493 "--matrix--%ld by %ld\n",
494 (long)mat->rows.size(),
495 (long)mat->columns.size());
496 }
497 // show_row_info();
498 // show_column_info();
499 // show_matrix();
500
501 // Now we reorder the columns, possibly rows?
503
504 // reorder_rows(); // This is only here so we can see what we are doing...?
505
506 // For debugging: let's compute the number of non-zero elements above the diagonal in A matrix.
507 // Also, let's compute the amount of space used for:
508 // column info
509 // row info
510 // sum of values in each row
511 // Maybe so A B C D matrices separately.
513}
514
516{
517 // Want:
518 // sizes of A, B, C, D.
519 // number of elements in each part.
520 // loop through the rows, and for each row, determine: in A or C?
521 // loop through elements in a row: for each, determine: in A/C or B/D
522
524
525 // look at 'mat', determine number of rows, cols, etc.
526 long nrows = mat->rows.size();
527 long ncols = mat->columns.size();
528 for (long i=0; i<nrows; ++i)
529 {
530 bool is_pivot = is_pivot_row(i);
531 if (is_pivot)
532 ++stats.mTopAndLeft;
533
534 auto& r = mat->rows[i];
535 for (long j=0; j < r.len; ++j)
536 {
537 auto c = r.comps[j];
538 bool is_left = mat->columns[c].head >= 0;
539 if (is_pivot and is_left) ++stats.mAEntries;
540 if (is_pivot and not is_left) ++stats.mBEntries;
541 if (not is_pivot and is_left) ++stats.mCEntries;
542 if (not is_pivot and not is_left) ++stats.mDEntries;
543 }
544 }
545
546 stats.mAEntries -= stats.mTopAndLeft;
547 stats.mBottom = nrows - stats.mTopAndLeft;
548 stats.mRight = ncols - stats.mTopAndLeft;
549
550 stats.display();
551 return stats;
552}
553
555{
556 if (M2_gbTrace >= 2)
557 {
558 std::ostringstream s;
559
560 s << "Quad matrix sizes" << std::endl;
561 s << "sizes of quad matrix" << std::endl;
562 s << std::setw(11) << " " << std::setw(11) << mTopAndLeft << std::setw(11) << mRight << std::endl;
563 s << std::setw(11) << mTopAndLeft << std::setw(11) << "A" << std::setw(11) << "B" << std::endl;
564 s << std::setw(11) << mBottom << std::setw(11) << "C" << std::setw(11) << "D" << std::endl;
565 s << std::endl;
566
567 if (M2_gbTrace >= 5)
568 {
569 s << "Quad matrix entries (no diagonal on A)" << std::endl;
570 s << std::setw(11) << " " << std::setw(11) << mTopAndLeft << std::setw(11) << mRight << std::endl;
571 s << std::setw(11) << mTopAndLeft << std::setw(11) << mAEntries << std::setw(11) << mBEntries << std::endl;
572 s << std::setw(11) << mBottom << std::setw(11) << mCEntries << std::setw(11) << mDEntries << std::endl;
573 s << std::endl;
574 }
575
576 o << s.str().c_str();
577 }
578}
579
581{
582 buffer o;
583 display(o);
584 emit(o.str());
585}
586
587
589// Gaussian elimination ///////////////////////////
592{
593 // If r.coeffs is set, returns that, otherwise returns the coeffs array from
594 // the generator or GB element. The resulting value should not be modified.
595 if (not r.coeffs.isNull() || r.len == 0) return r.coeffs;
596
597 // At this point, we must go find the coeff array
598 if (r.monom == nullptr) // i.e. a generator
599 return mGenerators[r.elem]->f.coeffs;
600 return mGroebnerBasis[r.elem]->f.coeffs;
601}
602
603bool F4GB::is_new_GB_row(int row) const
604// returns true if the r-th row has its lead term not in the current GB
605// This can be used to determine which elements should be reduced in the first
606// place and also to determine if an element (row) needs to be tail reduced
607{
608 row_elem &r = mat->rows[row];
609 return (r.len > 0 && not r.coeffs.isNull());
610}
611
612void F4GB::gauss_reduce(bool diagonalize)
613// This reduces the matrix to a triangular form
614{
615 // For each row which is a non-pivot row:
616 // note that the row must be reducible, since the lead term corresponds to an
617 // spair cancellation
618 // actually: not true: generators will often not be reducible...
619 // also each such row must be non-zero, for the same reason
620 int nrows = INTSIZE(mat->rows);
621 int ncols = INTSIZE(mat->columns);
622
623 int n_newpivots = -1; // the number of new GB elements in this degree
624 std::atomic<long> n_zero_reductions = 0;
625
626 mtbb::tick_count t0;
627 mtbb::tick_count t1;
628 std::vector<int> spair_rows;
629
630 if (hilbert)
631 {
632 n_newpivots = hilbert->nRemainingExpected();
633 if (n_newpivots == 0)
634 {
635 std::cout << "Oh crap, our logic is wrong: should not get here if no new GB elements expected in this degree" << std::endl;
636 return;
637 }
638 }
639
640 for (int i = 0; i < nrows; ++i)
641 {
642 if (not is_pivot_row(i))
643 spair_rows.push_back(i);
644 }
645
646 t0 = mtbb::tick_count::now();
647
648#if defined(WITH_TBB)
649
650 std::mutex cout_guard;
651 using threadLocalDense_t = mtbb::enumerable_thread_specific<ElementArray>;
652 // create a dense array for each thread
653 threadLocalDense_t threadLocalDense([&]() {
654 return mVectorArithmetic->allocateElementArray(ncols);
655 });
656
657 if (M2_gbTrace >= 2) {
658 // TODO: where to display this info
659 std::cout << "Number of Threads Used: " << mNumThreads << std::endl;
660 }
661
662 mScheduler.execute([&] {
663 mtbb::parallel_for(mtbb::blocked_range<int>{0, INTSIZE(spair_rows)},
664 [&](const mtbb::blocked_range<int>& r)
665 {
666 // long actual_reductions = 0;
667 // for (auto i = r.begin(); i != r.end(); ++i)
668 // {
669 // if (not is_pivot_row(i))
670 // ++ actual_reductions;
671 // }
672
673 // cout_guard.lock();
674 // std::cout << "#reductions to do: " << actual_reductions << std::endl;
675 // cout_guard.unlock();
676
677 threadLocalDense_t::reference my_dense = threadLocalDense.local();
678 for (auto i = r.begin(); i != r.end(); ++i)
679 {
680 bool newNonzeroReduction = gauss_reduce_row(spair_rows[i], my_dense);
681 }
682 });
683 });
684 for (auto tlDense : threadLocalDense)
685 mVectorArithmetic->deallocateElementArray(tlDense);
686
687#else
688
689 ElementArray my_dense { mVectorArithmetic->allocateElementArray(ncols) };
690
691 for (int i = 0; i < INTSIZE(spair_rows); ++i)
692 gauss_reduce_row(spair_rows[i], my_dense);
693
694 mVectorArithmetic->deallocateElementArray(my_dense);
695
696#endif
697
698 t1 = mtbb::tick_count::now();
699 mParallelGaussTime += (t1-t0).seconds();
700
701 if (M2_gbTrace >= 2)
702 std::cout << "About to do serial loop, n_newpivots = " << n_newpivots << std::endl;
703 t0 = mtbb::tick_count::now();
704 ElementArray gauss_row { mVectorArithmetic->allocateElementArray(ncols) };
705 for (auto i = 0; i < spair_rows.size(); i++)
706 {
707 auto this_row = spair_rows[i];
708 if ((not hilbert) or (n_newpivots > 0))
709 {
710 bool newNonzeroReduction = gauss_reduce_row(this_row, gauss_row);
711 if (newNonzeroReduction)
712 {
713 row_elem &r = mat->rows[this_row];
714 mVectorArithmetic->makeMonic(r.coeffs);
715 mat->columns[r.comps[0]].head = this_row;
716 if (hilbert) --n_newpivots;
717 }
718 else
719 ++n_zero_reductions;
720 } else if (hilbert)
721 {
722 // Inform code that we don't want a new GB element from this row.
723 // The row will be deleted with clear_matrix.
724 row_elem &r = mat->rows[this_row];
725 r.len = 0;
726 }
727 }
728 mVectorArithmetic->deallocateElementArray(gauss_row);
729 t1 = mtbb::tick_count::now();
730 mSerialGaussTime += (t1-t0).seconds();
731
732 if (M2_gbTrace >= 3)
733 fprintf(stderr, "-- #zeroreductions %ld\n", n_zero_reductions.load());
734
735 t0 = mtbb::tick_count::now();
736 if (diagonalize) tail_reduce();
737 t1 = mtbb::tick_count::now();
738 mTailReduceTime += (t1-t0).seconds();
739}
740
741bool F4GB::is_pivot_row(int index) const
742{
743 row_elem &r = mat->rows[index];
744 int pivotcol = r.comps[0];
745 int pivotrow = mat->columns[pivotcol].head;
746 return (pivotrow == index);
747}
748
750 ElementArray& gauss_row)
751{
752 // returns true if the row reduces to a "new" nonzero row
753 // returns false otherwise
754 row_elem &r = mat->rows[index];
755 if (r.len == 0) return false; // could happen once we include syzygies...
756 if (is_pivot_row(index)) return false;
757
758 int pivotcol = r.comps[0];
759 int pivotrow = mat->columns[pivotcol].head;
760
761 const ElementArray& rcoeffs = get_coeffs_array(r);
763 mVectorArithmetic->fillDenseArray(gauss_row, rcoeffs, Range(r.comps, r.comps + r.len));
764
765 int firstnonzero = -1;
766 int first = r.comps[0];
767 int last = r.comps[r.len - 1];
768 do
769 {
770 pivotrow = mat->columns[first].head;
771 if (pivotrow >= 0)
772 {
773 row_elem &pivot_rowelem = mat->rows[pivotrow];
774 auto& pivot_coeffs = get_coeffs_array(pivot_rowelem);
776 mVectorArithmetic->denseCancelFromSparse(gauss_row,
777 pivot_coeffs,
778 Range(pivot_rowelem.comps,
779 pivot_rowelem.comps + pivot_rowelem.len)
780 );
781 int last1 = pivot_rowelem.comps[pivot_rowelem.len - 1];
782 if (last1 > last) last = last1;
783 }
784 else if (firstnonzero == -1)
785 firstnonzero = first;
786 first = mVectorArithmetic->denseNextNonzero(gauss_row, first+1, last);
787 }
788 while (first <= last); // end do
789
790 if (not r.coeffs.isNull())
791 mVectorArithmetic->deallocateElementArray(r.coeffs);
792 //Mem->components.deallocate(r.comps);
793 delete [] r.comps;
794 r.comps = nullptr;
795 r.len = 0;
796 //Range<int> monomRange;
797 //mVectorArithmetic->denseToSparse(gauss_row, r.coeffs, monomRange, firstnonzero, last, mComponentSpace);
798 //mVectorArithmetic->denseToSparse(gauss_row, r.coeffs, r.comps, firstnonzero, last, Mem->components);
799 mVectorArithmetic->denseToSparse(gauss_row, r.coeffs, r.comps, firstnonzero, last);
800
801 // TODO set r.comps from monomRange. Question: who has allocated this space??
802 // Maybe for now it is just the following line:
803 r.len = mVectorArithmetic->size(r.coeffs);
804 //r.len = monomRange.size();
805 //r.comps = Mem->components.allocate(r.len);
806 //std::copy(monomRange.begin(), monomRange.end(), r.comps);
807 //mComponentSpace.freeTopArray(monomRange.begin(), monomRange.end());
808 //assert(r.len == mVectorArithmetic->size(r.coeffs));
809
810 // the above line leaves gauss_row zero, and also handles the case when
811 // r.len is 0 (TODO: check this!!)
812 // it also potentially frees the old r.coeffs and r.comps (TODO: ?? r.comps??)
813 return (r.len > 0);
814}
815
816
818{
819 int nrows = INTSIZE(mat->rows);
820 int ncols = INTSIZE(mat->columns);
821
822 ElementArray gauss_row { mVectorArithmetic->allocateElementArray(ncols) };
823 for (int i = nrows - 1; i >= 0; i--)
824 {
825 row_elem &r = mat->rows[i];
826 if (r.len <= 1 || r.coeffs.isNull())
827 continue; // row reduced to zero, ignore it.
828 // At this point, we should have an element to reduce
829 bool anychange = false;
830 mVectorArithmetic->fillDenseArray(gauss_row, r.coeffs, Range(r.comps,
831 r.comps + r.len));
832 int firstnonzero = r.comps[0];
833 int first = (r.len == 1 ? ncols : r.comps[1]);
834 int last = r.comps[r.len - 1];
835 while (first <= last)
836 {
837 int pivotrow = mat->columns[first].head;
838 if (pivotrow >= 0)
839 {
840 anychange = true;
841 row_elem &pivot_rowelem =
842 mat->rows[pivotrow]; // pivot_rowelems.coeffs is set at this
843 mVectorArithmetic->denseCancelFromSparse(gauss_row,
844 pivot_rowelem.coeffs,
845 Range(pivot_rowelem.comps,
846 pivot_rowelem.comps + pivot_rowelem.len));
847 int last1 = pivot_rowelem.comps[pivot_rowelem.len - 1];
848 if (last1 > last) last = last1;
849 }
850 else if (firstnonzero == ncols)
851 firstnonzero = first;
852 first = mVectorArithmetic->denseNextNonzero(gauss_row, first+1, last);
853 };
854 if (anychange)
855 {
856 //Mem->components.deallocate(r.comps);
857 delete [] r.comps;
858 mVectorArithmetic->deallocateElementArray(r.coeffs);
859 r.len = 0;
860 //Range<int> monomRange;
861 //mVectorArithmetic->denseToSparse(gauss_row,
862 // r.coeffs,
863 // monomRange,
864 // firstnonzero, last,
865 // mComponentSpace);
866 // mVectorArithmetic->denseToSparse(gauss_row,
867 // r.coeffs,
868 // r.comps,
869 // firstnonzero, last,
870 // Mem->components);
871 mVectorArithmetic->denseToSparse(gauss_row,
872 r.coeffs,
873 r.comps,
874 firstnonzero, last);
875 r.len = mVectorArithmetic->size(r.coeffs);
876 //r.len = monomRange.size();
877 //r.comps = Mem->components.allocate(r.len);
878 //std::copy(monomRange.begin(), monomRange.end(), r.comps);
879 //mComponentSpace.freeTopArray(monomRange.begin(), monomRange.end());
880 assert(r.len == mVectorArithmetic->size(r.coeffs));
881 }
882 else
883 {
884 mVectorArithmetic->setZeroInRange(gauss_row, firstnonzero, last);
885 }
886 if (r.len > 0)
887 {
888 mVectorArithmetic->makeMonic(r.coeffs);
889 }
890 }
891
892 mVectorArithmetic->deallocateElementArray(gauss_row);
893}
894
896// Extracting new GB elements //////////////////
898
900{
901 // Insert row as gb element.
902 // Actions to do:
903 // translate row to a gbelem + poly
904 // set degrees as needed
905 // insert the monomial into the lookup table
906 // find new pairs associated to this new element
907
908 int nslots = mMonomialInfo->max_monomial_size();
909 int nlongs = r.len * nslots;
910
911 gbelem *result = new gbelem;
912 result->f.len = r.len;
913
914 // If the coeff array is null, then that means the coeffs come from the
915 // original array
916 // Here we copy it over.
917
918 // const ElementArray& v = (not r.coeffs.isNull() ? r.coeffs : mVectorArithmetic->copyElementArray(get_coeffs_array(r)));
919 // result->f.coeffs.swap(v);
920 if (r.coeffs.isNull())
921 {
922 // this means the actual coeff vector is coming from a GB element. Copy it into result->f.coeffs
923 ElementArray v { mVectorArithmetic->copyElementArray(get_coeffs_array(r)) };
924 result->f.coeffs.swap(v);
925 }
926 else
927 {
928 result->f.coeffs.swap(r.coeffs);
929 }
930
931 //result->f.monoms = Mem->allocate_monomial_array(nlongs);
932 result->f.monoms = new monomial_word[nlongs];
933
934 monomial_word *nextmonom = result->f.monoms;
935 for (int i = 0; i < r.len; i++)
936 {
937 mMonomialInfo->copy(mat->columns[r.comps[i]].monom, nextmonom);
938 nextmonom += nslots;
939 }
940 // Mem->components.deallocate(r.comps);
941 delete [] r.comps;
942 r.comps = nullptr;
943 r.len = 0;
944 result->deg = this_degree;
945 result->alpha = static_cast<int>(mMonomialInfo->last_exponent(result->f.monoms));
946 result->minlevel = ELEM_MIN_GB; // MES: How do
947 // we distinguish between ELEM_MIN_GB, ELEM_POSSIBLE_MINGEN?
948
949 int which = INTSIZE(mGroebnerBasis);
950 mGroebnerBasis.push_back(result);
951
952 if (hilbert)
953 {
954 int x;
955 //int *exp = newarray_atomic(int, M->n_vars());
956 int *exp = new int[mMonomialInfo->n_vars()];
957 mMonomialInfo->to_intstar_vector(result->f.monoms, exp, x);
958 hilbert->addMonomial(exp, x + 1);
959 delete [] exp;
960 //freemem(exp);
961 }
962 // now insert the lead monomial into the lookup table
963 //varpower_monomial vp = newarray_atomic(varpower_word, 2 * M->n_vars() + 1);
964 varpower_monomial vp = new varpower_word[2 * mMonomialInfo->n_vars() + 1];
965 mMonomialInfo->to_varpower_monomial(result->f.monoms, vp);
966 mLookupTable.insert_minimal_vp(mMonomialInfo->get_component(result->f.monoms), vp, which);
967 delete [] vp;
968 //freemem(vp);
969 // now go forth and find those new pairs
970 mtbb::tick_count t0 = mtbb::tick_count::now();
971 mSPairSet.find_new_pairs(is_ideal);
972 mtbb::tick_count t1 = mtbb::tick_count::now();
973 mNewSPairTime += (t1-t0).seconds();
974}
975
977{
978 /* After LU decomposition, loop through each
979 row of the matrix. If the corresponding
980 lead term is not in the initial ideal (or, at least,
981 wasn't) then insert GB element (and so update spairs, etc,
982 but don't do auto_reduce...)
983
984 If instead the lead term is not new, then keep track of this
985 information somehow: place ... into a monheap...
986 */
987
988 /* If we can place the possible new elements first, or in a separate place,
989 then
990 we don't need to loop through all of these */
991
992 mtbb::tick_count t0 = mtbb::tick_count::now();
993 for (int r = 0; r < mat->rows.size(); r++)
994 {
995 if (is_new_GB_row(r))
996 {
997 insert_gb_element(mat->rows[r]);
998 }
999 }
1000 mtbb::tick_count t1 = mtbb::tick_count::now();
1001 mInsertGBTime += (t1-t0).seconds();
1002}
1003
1005// Top level algorithm logic //////////////////
1007
1009{
1010 if (hilbert && hilbert->nRemainingExpected() == 0)
1011 {
1012 mSPairSet.discardSPairsInCurrentDegree();
1013 if (M2_gbTrace >= 1)
1014 fprintf(stderr,
1015 "-- skipping degree...no elements expected in this degree\n");
1016 return;
1017 }
1018 reset_matrix();
1019 clock_t begin_time = clock();
1020
1021 n_lcmdups = 0;
1022 make_matrix();
1023
1024 if (M2_gbTrace >= 6)
1025 {
1026 fprintf(stderr, "---------\n");
1027 show_matrix();
1028 fprintf(stderr, "---------\n");
1029 }
1030
1031 clock_t end_time = clock();
1032 clock_make_matrix += end_time - begin_time;
1033 double nsecs = static_cast<double>(end_time - begin_time);
1034 nsecs /= CLOCKS_PER_SEC;
1035 if (M2_gbTrace >= 2) fprintf(stderr, " make matrix time = %f\n", nsecs);
1036
1037 if (M2_gbTrace >= 3) mMonomialHashTable.dump();
1038
1039 double oldParallelGauss = mParallelGaussTime;
1040 double oldSerialGauss = mSerialGaussTime;
1041 double oldTailReduce = mTailReduceTime;
1042 double oldNewSPair = mNewSPairTime;
1043 double oldInsertNewGB = mInsertGBTime;
1044
1045 begin_time = clock();
1046 gauss_reduce(true);
1047 end_time = clock();
1048 clock_gauss += end_time - begin_time;
1049
1050 // fprintf(stderr, "---------\n");
1051 // show_matrix();
1052 // fprintf(stderr, "---------\n");
1053
1054 nsecs = static_cast<double>(end_time - begin_time);
1055 nsecs /= CLOCKS_PER_SEC;
1056 if (M2_gbTrace >= 2)
1057 {
1058 fprintf(stderr, " gauss time = %f\n", nsecs);
1059 fprintf(stderr, " parallel gauss time = %g\n", mParallelGaussTime - oldParallelGauss);
1060 fprintf(stderr, " serial gauss time = %g\n", mSerialGaussTime - oldSerialGauss);
1061 fprintf(stderr, " tail reduce time = %g\n", mTailReduceTime - oldTailReduce);
1062
1063 fprintf(stderr, " lcm dups = %ld\n", n_lcmdups);
1064 if (M2_gbTrace >= 6)
1065 {
1066 fprintf(stderr, "---------\n");
1067 show_matrix();
1068 fprintf(stderr, "---------\n");
1069 }
1070 }
1072 if (M2_gbTrace >= 2)
1073 {
1074 fprintf(stderr, " finding new spair time = %g\n", mNewSPairTime - oldNewSPair);
1075 fprintf(stderr, " number of spairs in queue = %zu\n", mSPairSet.numberOfSPairs());
1076 fprintf(stderr, " insert new gb time = %g\n", mInsertGBTime - oldInsertNewGB - (mNewSPairTime - oldNewSPair));
1077 }
1078
1079 int ngb = INTSIZE(mGroebnerBasis);
1080 if (M2_gbTrace >= 1)
1081 {
1082 fprintf(stderr, " # GB elements = %d\n", ngb);
1083 if (M2_gbTrace >= 5) {
1085 mSPairSet.display();
1086 }
1087 }
1088
1089 clear_matrix();
1090}
1091
1093{
1094 // This handles everything but stop_.always, stop_.degree_limit
1095 if (stop_.basis_element_limit > 0 && mGroebnerBasis.size() >= stop_.basis_element_limit)
1096 return COMP_DONE_GB_LIMIT;
1097 if (stop_.pair_limit > 0 && n_pairs_computed >= stop_.pair_limit)
1098 return COMP_DONE_PAIR_LIMIT;
1099 if (stop_.just_min_gens && n_gens_left == 0) return COMP_DONE_MIN_GENS;
1100 if (stop_.subring_limit > 0 && n_subring >= stop_.subring_limit)
1102 if (stop_.use_codim_limit)
1103 {
1104#ifdef DEVELOPMENT
1105#warning "compute the codimension"
1106#endif
1107 int c = 0; // replace this line
1108 // int c = codim_of_lead_terms();
1109 if (c >= stop_.codim_limit) return COMP_DONE_CODIM;
1110 }
1111 return COMP_COMPUTING;
1112}
1113
1115{
1116 // This starts out with taking each generator and placing it into the
1117 // gb matrix, and then calling find_new_pairs after each one.
1118 // It displays the list of spairs after each generator.
1119
1120 mGroebnerBasis.push_back(mGenerators[0]);
1121 for (int i = 1; i < mGenerators.size(); i++)
1122 {
1123 mGroebnerBasis.push_back(mGenerators[i]);
1124 mSPairSet.find_new_pairs(false);
1125 fprintf(stderr, "---Just inserted element %d---\n", i);
1126 mSPairSet.display();
1127 }
1128}
1129
1131{
1133 clock_gauss = 0;
1135 int npairs = 0;
1136
1137 // test_spair_code();
1138
1140
1141 for (;;)
1142 {
1143 if (system_interrupted())
1144 {
1145 is_done = COMP_INTERRUPTED;
1146 break;
1147 }
1148
1149 is_done = computation_is_complete(stop_);
1150 if (is_done != COMP_COMPUTING) break;
1151
1152 //this_degree = mSPairSet.prepare_next_degree(-1, npairs);
1153 auto thisDegInfo = mSPairSet.setThisDegree();
1154
1155 if (not thisDegInfo.first)
1156 {
1157 is_done = COMP_DONE;
1158 break;
1159 }
1160
1161 this_degree = thisDegInfo.second;
1162
1163 if (stop_.stop_after_degree && this_degree > stop_.degree_limit->array[0])
1164 {
1165 is_done = COMP_DONE_DEGREE_LIMIT;
1166 break;
1167 }
1168
1169 if (hilbert)
1170 {
1171 if (!hilbert->setDegree(this_degree))
1172 {
1173 if (error())
1174 is_done = COMP_ERROR;
1175 else
1176 is_done = COMP_INTERRUPTED;
1177 break;
1178 }
1179 }
1180
1181 if (M2_gbTrace >= 1)
1182 {
1183 if (hilbert)
1184 fprintf(stderr,
1185 "DEGREE %d (nexpected %d npairs %d)\n",
1187 hilbert->nRemainingExpected(),
1188 npairs);
1189 else
1190 fprintf(stderr, "DEGREE %d (npairs %d)\n", this_degree, npairs);
1191 }
1192 do_spairs();
1194 }
1195
1196 if (M2_gbTrace >= 2)
1197 {
1198 // fprintf(stderr,
1199 // "number of calls to cancel row : %ld\n",
1200 // mGausser->n_dense_row_cancel);
1201 // fprintf(stderr,
1202 // "number of calls to subtract_multiple: %ld\n",
1203 // mGausser->n_subtract_multiple);
1204 fprintf(
1205 stderr, "total time for sorting columns: %f\n", clock_sort_columns);
1206 fprintf(stderr,
1207 "total time for making matrix (includes sort): %f\n",
1208 ((double)clock_make_matrix) / CLOCKS_PER_SEC);
1209 fprintf(stderr,
1210 "total time for gauss: %f\n",
1211 ((double)clock_gauss) / CLOCKS_PER_SEC);
1212 fprintf(stderr,
1213 "parallel tbb time for gauss: %g\n",
1215 fprintf(stderr,
1216 "serial tbb time for gauss: %g\n",
1218 fprintf(stderr,
1219 "total time for finding new spairs: %g\n",
1221 fprintf(stderr,
1222 "total time for creating pre spairs: %g\n",
1223 mSPairSet.secondsToCreatePrePairs());
1224 fprintf(stderr,
1225 "total time for minimizing new spairs: %g\n",
1226 mSPairSet.secondsToMinimizePairs());
1227 fprintf(stderr,
1228 "total time for inserting new gb elements: %g\n",
1230 fprintf(stderr,
1231 "number of spairs computed : %ld\n",
1233 fprintf(stderr,
1234 "number of reduction steps : %ld\n",
1236 if (M2_gbTrace >= 3)
1237 {
1238 fprintf(stderr,
1239 "number of spairs removed by criterion = %ld\n",
1240 mSPairSet.n_unneeded_pairs());
1241 mMonomialInfo->show();
1242 }
1243 }
1244
1245 return is_done;
1246}
1247
1249// Debugging routines only ///////
1251
1252
1253void F4GB::show_gb_array(const gb_array &g) const
1254{
1255 // Debugging routine
1256 // Display the array, and all of the internal information in it too.
1257 buffer o;
1258 for (int i = 0; i < g.size(); i++)
1259 {
1262 o << "element " << i << " degree " << g[i]->deg << " alpha "
1263 << g[i]->alpha << newline << " ";
1264 mFreeModule->get_ring()->vec_text_out(o, v);
1265 o << newline;
1266 }
1267 emit(o.str());
1268}
1269
1271{
1272 // Debugging routine
1273 for (int i = 0; i < mat->rows.size(); i++)
1274 {
1275 fprintf(stderr, "%4d ", mat->rows[i].elem);
1276 if (mat->rows[i].monom == nullptr)
1277 fprintf(stderr, "generator");
1278 else
1279 mMonomialInfo->show(mat->rows[i].monom);
1280 fprintf(stderr, "\n");
1281 }
1282}
1283
1285{
1286 mMonomialInfo->show();
1287 // Debugging routine
1288 for (int i = 0; i < mat->columns.size(); i++)
1289 {
1290 fprintf(stderr, "head %4d monomial ", mat->columns[i].head);
1291 mMonomialInfo->show(mat->columns[i].monom);
1292 fprintf(stderr, "\n");
1293 }
1294}
1295
1297{
1298 // Debugging routine
1301 buffer o;
1302 q->text_out(o);
1303 emit(o.str());
1304}
1305
1307{
1308 int ncols = INTSIZE(mat->columns);
1309 int nrows = 0;
1310 for (int nr = 0; nr < mat->rows.size(); nr++)
1311 if (is_new_GB_row(nr)) nrows++;
1312
1313 MutableMatrix *gbM =
1314 IM2_MutableMatrix_make(mVectorArithmetic->ring(), nrows, ncols, false);
1315
1316 int r = -1;
1317 for (int nr = 0; nr < mat->rows.size(); nr++)
1318 if (is_new_GB_row(nr))
1319 {
1320 r++;
1321 row_elem &row = mat->rows[nr];
1322 auto& coeffs = get_coeffs_array(row);
1323 for (int i = 0; i < row.len; i++)
1324 {
1325 int c = row.comps[i];
1326 ring_elem a = mVectorArithmetic->ringElemFromElementArray(coeffs, i);
1327 gbM->set_entry(r, c, a);
1328 }
1329 }
1330
1331 buffer o;
1332 gbM->text_out(o);
1333 emit(o.str());
1334}
1335
1336template class F4MemoryBlock<monomial_word>;
1337template class F4MemoryBlock<pre_spair>;
1338
1339// Local Variables:
1340// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
1341// indent-tabs-mode: nil
1342// End:
Append-only GC-backed byte buffer used throughout the engine for text output.
static long ncmps0
Definition f4-types.hpp:207
void reset_ncomparisons()
Definition f4-types.hpp:229
static long ncmps
Definition f4-types.hpp:206
long ncomparisons0() const
Definition f4-types.hpp:228
Comparator that orders Macaulay-matrix column indices by the monomial each column represents,...
Definition f4-types.hpp:197
bool isNull() const
Type-erased owning handle to a dense coefficient vector held by a ConcreteVectorArithmetic<Ring>.
void set_hilbert_function(const RingElement *hf)
Definition f4.cpp:94
void tail_reduce()
Definition f4.cpp:817
int next_col_to_process
Definition f4.hpp:185
int mult_monomials(packed_monomial m, packed_monomial n)
Definition f4.cpp:177
const ElementArray & get_coeffs_array(row_elem &r)
Definition f4.cpp:591
double mNewSPairTime
Definition f4.hpp:200
double mSerialGaussTime
Definition f4.hpp:198
void show_new_rows_matrix()
Definition f4.cpp:1306
M2_arrayint component_degrees
Definition f4.hpp:161
F4MemoryBlock< monomial_word > mMonomialMemoryBlock
Definition f4.hpp:188
void delete_gb_array(gb_array &g)
Definition f4.cpp:99
clock_t clock_gauss
Definition f4.hpp:195
coefficient_matrix * mat
Definition f4.hpp:186
int complete_thru_this_degree
Definition f4.hpp:170
enum ComputationStatusCode start_computation(StopConditions &stop_)
Definition f4.cpp:1130
void show_gb_array(const gb_array &g) const
Definition f4.cpp:1253
gb_array mGenerators
Definition f4.hpp:180
bool is_new_GB_row(int row) const
Definition f4.cpp:603
F4GB(const VectorArithmetic *VA, const MonomialInfo *MI, const FreeModule *F, M2_bool collect_syz, int n_rows_to_keep, M2_arrayint gb_weights, int strategy, M2_bool use_max_degree, int max_degree, int numThreads)
Definition f4.cpp:33
double mTailReduceTime
Definition f4.hpp:199
void new_generators(int lo, int hi)
Definition f4.cpp:139
F4SPairSet mSPairSet
Definition f4.hpp:249
MacaulayMatrixStats macaulayMatrixStats() const
Definition f4.cpp:515
void test_spair_code()
Definition f4.cpp:1114
monomial_word * next_monom
Definition f4.hpp:189
clock_t clock_make_matrix
Definition f4.hpp:202
HilbertController * hilbert
Definition f4.hpp:175
long n_pairs_computed
Definition f4.hpp:166
void reset_matrix()
Definition f4.cpp:438
void load_row(packed_monomial monom, int which)
Definition f4.cpp:220
int find_or_append_column(packed_monomial m)
Definition f4.cpp:165
void show_column_info() const
Definition f4.cpp:1284
void do_spairs()
Definition f4.cpp:1008
bool is_pivot_row(int index) const
Definition f4.cpp:741
int n_subring
Definition f4.hpp:169
int n_gens_left
Definition f4.hpp:168
void show_row_info() const
Definition f4.cpp:1270
void reorder_columns()
Definition f4.cpp:322
const MonomialInfo * mMonomialInfo
Definition f4.hpp:157
double mInsertGBTime
Definition f4.hpp:201
long n_lcmdups
Definition f4.hpp:165
void reorder_rows()
Definition f4.cpp:409
enum ComputationStatusCode computation_is_complete(StopConditions &stop_)
Definition f4.cpp:1092
void poly_set_degrees(const GBF4Polynomial &f, int &deg_result, int &alpha) const
Definition f4.cpp:121
~F4GB()
Definition f4.cpp:110
void load_gen(int which)
Definition f4.cpp:196
void loadReducerRow(spair *p)
Definition f4.cpp:280
const FreeModule * mFreeModule
Definition f4.hpp:158
int this_degree
Definition f4.hpp:171
double clock_sort_columns
Definition f4.hpp:194
void gauss_reduce(bool diagonalize)
Definition f4.cpp:612
MonomialLookupTable mLookupTable
Definition f4.hpp:182
void process_s_pair(spair *p)
Definition f4.cpp:290
void insert_gb_element(row_elem &r)
Definition f4.cpp:899
double mParallelGaussTime
Definition f4.hpp:197
double mGaussTime
Definition f4.hpp:196
MonomialHashTable< MonomialInfo > mMonomialHashTable
Definition f4.hpp:187
void clear_matrix()
Definition f4.cpp:446
void process_column(int c)
Definition f4.cpp:243
void make_matrix()
Definition f4.cpp:469
long n_reduction_steps
Definition f4.hpp:167
void loadSPairRow(spair *p)
Definition f4.cpp:270
const VectorArithmetic * mVectorArithmetic
Definition f4.hpp:156
void show_matrix()
Definition f4.cpp:1296
int new_column(packed_monomial m)
Definition f4.cpp:153
void new_GB_elements()
Definition f4.cpp:976
bool is_ideal
Definition f4.hpp:172
gb_array mGroebnerBasis
Definition f4.hpp:181
bool gauss_reduce_row(int index, ElementArray &gauss_row)
Definition f4.cpp:749
static MutableMatrix * to_M2_MutableMatrix(const VectorArithmetic *VA, coefficient_matrix *mat, gb_array &gens, gb_array &gb)
static vec to_M2_vec(const VectorArithmetic *VA, const MonomialInfo *MI, const GBF4Polynomial &f, const FreeModule *F)
Engine-side free module R^n over a Ring.
Definition freemod.hpp:66
Hilbert-function-driven early termination helper used by F4GB to skip degrees the user-supplied Hilbe...
Definition hilb-fcn.hpp:57
Per-ring monomial layout / encoding helper used by F4GB.
Definition moninfo.hpp:108
void text_out(buffer &o) const
Definition mat.cpp:89
virtual bool set_entry(size_t r, size_t c, const ring_elem a)=0
Abstract base class for mutable matrices over an arbitrary engine Ring, the in-place counterpart of t...
Definition mat.hpp:79
Front-end-visible "ring element" value: an engine ring_elem paired with the Ring* that gives it meani...
Definition relem.hpp:67
Runtime dispatcher that hides the concrete coefficient ring behind a std::variant of ConcreteVectorAr...
char * str()
Definition buffer.hpp:72
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_COMPUTING
Definition computation.h:71
@ COMP_INTERRUPTED
Definition computation.h:57
int error()
Definition error.c:48
Engine error-reporting primitives: ERROR, INTERNAL_ERROR, error, error_message.
F4toM2Interface — static translators between engine vec / Matrix and F4's GBF4Polynomial.
F4SPairSet — priority-queue + pruning logic for F4 S-pairs.
std::vector< gbelem * > gb_array
Definition f4-types.hpp:145
@ ELEM_MIN_GB
Definition f4-types.hpp:76
Shared type vocabulary used across the F4 engine.
F4GB — the inner-loop Faugère F4 Groebner-basis algorithm.
FreeModule — finite-rank free module R^n, the type-level anchor for every Matrix.
int p
HilbertController — early-exit driver for F4 given a known Hilbert series.
bool system_interrupted()
system_interrupted() — thread-safe polling predicate for Ctrl+C handling.
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
char M2_bool
Definition m2-types.h:82
MutableMatrix — abstract base of every mutable matrix the engine hands across the boundary.
F4MemoryBlock<T, NSLAB> — F4's templated slab bump allocator.
MonomialHashTable<ValueType> — open-addressing intern table for F4 and resolution monomials.
monomial_word * packed_monomial
Definition moninfo.hpp:78
long monomial_word
Definition moninfo.hpp:77
MonomialInfo — F4's packed_monomial encoding plus operations.
MutableMatrix * IM2_MutableMatrix_make(const Ring *R, int nrows, int ncols, M2_bool is_dense)
Engine-boundary C API for the engine's in-place MutableMatrix, including dense linear algebra.
void swap(mpfr::mpreal &x, mpfr::mpreal &y)
Definition mpreal.h:3244
volatile int x
Ring — the legacy abstract base class for every coefficient and polynomial ring.
ring_elem — the universal value type carried by every Ring* in the engine.
void display(buffer &o)
Definition f4.cpp:554
Per-degree counters describing the shape and density of the Macaulay matrix that F4GB just built.
Definition f4.hpp:218
monomial_word * monoms
Definition f4-types.hpp:110
Compact polynomial layout used inside the F4 GB engine.
Definition f4-types.hpp:107
unsigned int subring_limit
Definition computation.h:99
M2_bool use_codim_limit
Definition computation.h:97
M2_bool just_min_gens
unsigned int codim_limit
Definition computation.h:98
unsigned int basis_element_limit
Definition computation.h:94
M2_bool stop_after_degree
Definition computation.h:92
unsigned int pair_limit
Definition computation.h:96
M2_arrayint degree_limit
Definition computation.h:93
Bundle of optional early-termination knobs the front end can attach to a long-running Computation.
Definition computation.h:90
std::vector< column_elem > column_array
Definition f4-types.hpp:176
std::vector< row_elem > row_array
Definition f4-types.hpp:175
packed_monomial monom
Definition f4-types.hpp:168
int alpha
Definition f4-types.hpp:141
GBF4Polynomial f
Definition f4-types.hpp:139
int deg
Definition f4-types.hpp:140
packed_monomial monom
Definition f4-types.hpp:157
int * comps
Definition f4-types.hpp:163
ElementArray coeffs
Definition f4-types.hpp:162
#define INTSIZE(a)
Definition style.hpp:37
Engine-wide stylistic constants: LT / EQ / GT codes, INTSIZE, GEOHEAP_SIZE.
void emit(const char *s)
Definition text-io.cpp:41
Text-formatting helpers layered on buffer: bignum print, line wrapping, M2_gbTrace-gated emit.
double seconds(DurationType time_diff)
Definition timing.hpp:59
varpower_word * varpower_monomial
varpower_monomials::Exponent varpower_word
F4's (variable, exponent) sparse-monomial ExponentList specialisation (legacy).