Macaulay2 Engine
Loading...
Searching...
No Matches
res-schreyer-frame.cpp
Go to the documentation of this file.
1// Copyright 2014-2016 Michael E. Stillman
2
4
5#include "error.h" // for ERROR
6#include "f4/moninfo.hpp" // for monomial_word
7#include "interface/computation.h" // for StopConditions
8#include "schreyer-resolution/res-f4.hpp" // for F4Res
9#include "schreyer-resolution/res-f4-monlookup.hpp" // for ResF4Monomi...
10#include "schreyer-resolution/res-monomial-types.hpp" // for res_varpowe...
11#include "style.hpp" // for LT, GT
12#include "timing.hpp" // for timer, seconds
13
14#include <cassert> // for assert
15#include <cstdint> // for int32_t
16#include <algorithm> // for stable_sort
17#include <chrono> // for common_type...
18#include <iomanip> // for operator<<
19#include <iostream> // for operator<<
20#include <type_traits> // for swap
21
22namespace {
23class PreElementSorter
24{
25 public:
26 typedef SchreyerFrameTypes::PreElement* value;
27
28 private:
29 static long ncmps;
30
31 public:
32 int compare(value a, value b)
33 {
34 ncmps++;
35 if (a->degree > b->degree) return GT;
36 if (a->degree < b->degree) return LT;
37 return res_varpower_monomials::compare(a->vp, b->vp);
38 }
39
40 bool operator()(value a, value b)
41 {
42 ncmps++;
43 if (a->degree > b->degree) return false;
44 if (a->degree < b->degree) return true;
45 return res_varpower_monomials::compare(a->vp, b->vp) == LT;
46 }
47
48 PreElementSorter() {}
49 void reset_ncomparisons() { ncmps = 0; }
50 long ncomparisons() const { return ncmps; }
51 ~PreElementSorter() {}
52};
53
54long PreElementSorter::ncmps = 0;
55};
56
57SchreyerFrame::SchreyerFrame(const ResPolyRing& R, int max_level, int numThreads, bool parallelizeByDegree)
58 : mRing(R),
64 mComputer(new F4Res(*this)),
65 mNumThreads(mtbb::numThreads(numThreads)),
66 mParallelizeByDegree(parallelizeByDegree)
67#if defined(WITH_TBB)
68 , mScheduler(mNumThreads)
69 , mDepGraph(this)
70#endif
71{
72 mFrame.mLevels.resize(max_level + 1);
73 mMaxVPSize = 2 * monoid().n_vars() + 1;
74
75 timeMakeMatrix = 0.0;
76 timeSortMatrix = 0.0;
78 timeGaussMatrix = 0.0;
79 timeClearMatrix = 0.0;
81 timeComputeRanks = 0.0;
83
84 //std::cout << "hardware tbb threads: " << tbb::info::default_concurrency() << std::endl;
85 //std::cout << "hardware threads: " << std::thread::hardware_concurrency() << std::endl;
86 //std::cout << "using " << mNumThreads << " threads" << std::endl;
87}
88
89// Destruct the frame
91{
92 // Nothing to do here yet
93
94 // the monomial block will free itself
95 // as will the std::vector's
96
97 // NO!! what about the frame polynomials??
98}
99
100// Computes the entire frame, unless interrupted.
101// Returns true if whole frame has been completed, otherwise returns false.
103{
104 if (mState == Initializing)
105 {
106 std::cout << "error: calling computeFrame too soon" << std::endl;
107 }
108 if (mState != Frame) return true; // already computed
109
110 // Uses mCurrentLevel
111 while (mCurrentLevel < mFrame.mLevels.size())
112 {
113 if (M2_gbTrace >= 1)
114 std::cout << "maxsize = " << mFrame.mLevels.size()
115 << " and mCurrentLevel = " << mCurrentLevel << std::endl;
116 if (computeNextLevel() == 0) break; // increments mCurrentLevel
117 // if (interrupted) return false;
118 }
119 // show(-1);
120 // Now change the state of the computation
121
123 mCurrentLevel = 2;
126 setBettiDisplays(); // Also sets mMinimalizeTODO
127 if (M2_gbTrace >= 1)
128 {
129 std::cout << "non-minimal betti: " << std::endl;
130 mBettiNonminimal.output();
131 }
132
133 // for (int i=0; i<mMinimalizeTODO.size(); i++)
134 // {
135 // auto a = mMinimalizeTODO[i];
136 // std::cout << "(" << a.first << "," << a.second << ") ";
137 // }
138 // std::cout << std::endl;
139 return true;
140}
142 int top_slanted_degree,
143 int length_limit)
144{
145 // The lo degree will be: mLoSlantedDegree.
146 // The highest slanted degree will either be mHiSlantedDegree, or
147 // top_slanted_degree (minimum of these two).
148 // The length we need to compute to is either maxLevel(), or length_limit+1.
149 // We set maxlevel to length_limit. We insist that length_limit <= maxLevel()
150 // - 2.
151 // Here is what needs to be computed:
152 // lo: . . . . . . .
153 // . . . . . . .
155 // Each dot in all rows other than 'hi' needs to have syzygies computed for
156 // it.
157 // if hi == mHiSlantedDegree, then we do NOT need to compute syzygies in this
158 // last row.
159 // else we need to compute syzygies in these rows, EXCEPT not at level
160 // maxlevel+1
161
162 computeFrame();
163
164 int top_degree; // slanted degree
165 if (stop_after_degree)
166 {
167 top_degree = std::min(top_slanted_degree, mHiSlantedDegree);
168 top_degree = std::max(mLoSlantedDegree, top_degree);
169 }
170 else
171 {
172 top_degree = mHiSlantedDegree;
173 }
174 // First: if length_limit is too low, extend the Frame
175 if (length_limit >= maxLevel())
176 {
177 std::cout << "WARNING: cannot extend resolution length" << std::endl;
178 length_limit = maxLevel() - 1;
179 // Extend the length of the Frame, change mMaxLength, possibly
180 // mHiSlantedDegree
181 // increase mComputationStatus if needed, mMinimalBetti, ...
182 // computeFrame()
183 }
184 // std::cout << "std::min(mMaxLength-1, length_limit): " << mMaxLength-1 << " " << length_limit << std::endl;
185 // length_limit = std::min(mMaxLength-1, length_limit);
186
187#if defined(WITH_TBB)
188 // build the dependency graph
190 {
191 //std::cout << "In dep graph" << std::endl;
192 mScheduler.execute([&] {
193 makeDependencyGraph(mDepGraph,length_limit+1,top_degree - mLoSlantedDegree+1,true);
194 mDepGraph.startComputation();
195 mDepGraph.waitForCompletion();
196 });
197 //std::cout << "Out dep graph" << std::endl;
198 }
199 // If this is not run, the 'computeRanks' calls below compute all of these elements
200#endif
201
202 // What needs to be computed?
203 // lodeg..hideg, level: 0..maxlevel. Note: need to compute at level
204 // maxlevel+1 in order to get min betti numbers at
205 // level maxlevel.
206 // Also note: if hideg is the highest degree that occurs in the frame, we do
207 // not need to compute any matrices for these.
208
209 // std::cout << "res-schreyer-frame:208, mLoSlantedDegree, top_degree, "
210 // "length_limit, mMaxLength: "
211 // << mLoSlantedDegree << " " << top_degree << " " << length_limit << " " << mMaxLength << std::endl;
212
213 for (int deg = mLoSlantedDegree; deg <= top_degree - 1; deg++)
214 for (int lev = 1; lev <= length_limit + 1; lev++)
215 {
216 computeRank(deg, lev);
217 }
218
219 for (int lev = 1; lev <= length_limit; lev++)
220 {
221 computeRank(top_degree, lev);
222 }
223
224 if (M2_gbTrace >= 1)
225 {
226 std::cout << "displaying stats" << std::endl;
228 monoid().show();
229 std::cout << "total setPoly: " << ResPolynomialConstructor::ncalls << std::endl;
230 std::cout << "total setPolyFromArray: "
232 std::cout << "total ~ResPolynomial: " << ResPolynomial::npoly_destructor << std::endl;
233
234 std::cout << "total time for make matrix: " << timeMakeMatrix
235 << std::endl;
236 std::cout << "total time for sort matrix: " << timeSortMatrix
237 << std::endl;
238 std::cout << "total time for reorder matrix: " << timeReorderMatrix
239 << std::endl;
240 std::cout << "total time for gauss matrix: " << timeGaussMatrix
241 << std::endl;
242 std::cout << "total time for clear matrix: " << timeClearMatrix
243 << std::endl;
244 std::cout << "total time for reset hash table: " << timeResetHashTable
245 << std::endl;
246 std::cout << "total time for computing ranks: " << timeComputeRanks
247 << std::endl;
248 std::cout << "total time for computing sparse ranks: " << timeComputeSparseRanks
249 << std::endl;
250 }
251
252 BettiDisplay B(mBettiMinimal); // copy
253 // std::cout << "in res-schreyer-frame.cpp, minimalBettiNumbers A\n";
254 // B.output();
255 B.resize(mLoSlantedDegree, top_degree, length_limit);
256 // std::cout << "in res-schreyer-frame.cpp, minimalBettiNumbers B\n";
257 // B.output();
258 // std::cout << "mMaxLength, mLevels.size(): " << mMaxLength << " " << mFrame.mLevels.size() << std::endl;
259 return B;
260}
261
263{
264 // This is the computation of the non-minimal maps themselves
265 decltype(timer()) timeA, timeB;
266 // if (level(0).size() == 0)
267 // mState = Done;;
268 computeFrame();
269 if (M2_gbTrace >= 1)
270 {
271 std::cout << "computation status after computing frame: " << std::endl;
272 mComputationStatus.output();
273 }
274
275 int top_slanted_degree = mHiSlantedDegree;
276 if (stop.stop_after_degree and mHiSlantedDegree > stop.degree_limit->array[0])
277 top_slanted_degree = stop.degree_limit->array[0];
278
279#if defined(WITH_TBB)
280 // build the dependency graph
282 {
283 //std::cout << "In dep graph" << std::endl;
284 mScheduler.execute([&] {
285 makeDependencyGraph(mDepGraph,
286 mMaxLength+1,
287 top_slanted_degree - mLoSlantedDegree + 1,
288 false);
289 mDepGraph.startComputation();
290 mDepGraph.waitForCompletion();
291 });
292 //std::cout << "Out dep graph" << std::endl;
293 }
294 else
295 computeSyzygies(top_slanted_degree, mMaxLength);
296#else
297 computeSyzygies(top_slanted_degree, mMaxLength);
298#endif
299
300 if (M2_gbTrace >= 1)
301 {
303 std::cout << "total time for make matrix: " << timeMakeMatrix
304 << std::endl;
305 std::cout << "total time for sort matrix: " << timeSortMatrix
306 << std::endl;
307 std::cout << "total time for reorder matrix: " << timeReorderMatrix
308 << std::endl;
309 std::cout << "total time for gauss matrix: " << timeGaussMatrix
310 << std::endl;
311 std::cout << "total time for clear matrix: " << timeClearMatrix
312 << std::endl;
313 std::cout << "total time for reset hash table: " << timeResetHashTable
314 << std::endl;
315 std::cout << "total time for computing ranks: " << timeComputeRanks
316 << std::endl;
317 std::cout << "total time for computing sparse ranks: " << timeComputeSparseRanks
318 << std::endl;
319 }
320
321 return;
322#if 0
323 if (M2_gbTrace >= 1)
324 {
325 std::cout << "computation status after computing syzygies: " << std::endl;
326 mComputationStatus.output();
327 }
328 timeA = timer();
330 timeB = timer();
331 timeComputeRanks += seconds(timeB-timeA);
332 if (M2_gbTrace >= 1)
333 {
334 std::cout << "computation status after computing ranks: " << std::endl;
335 mComputationStatus.output();
336 }
337
338
339 // This next part needs to be computed after the frame, as otherwise mHiSlantedDegree isn't yet set.
340 int top_slanted_degree = 0;
341
342 top_slanted_degree = mHiSlantedDegree;
343 if (stop.stop_after_degree and mHiSlantedDegree > stop.degree_limit->array[0])
344 top_slanted_degree = stop.degree_limit->array[0];
345
346 while (true)
347 {
348 switch (mState) {
349 case Initializing:
350 break;
351 case Frame:
352 std::cerr << "ERROR: should not get to this point anymore..." << std::endl;
353 if (M2_gbTrace >= 1)
354 std::cout << "maxsize = " << mFrame.mLevels.size() << " and mCurrentLevel = " << mCurrentLevel << std::endl;
355 if (mCurrentLevel >= mFrame.mLevels.size() or computeNextLevel() == 0)
356 {
357 //show(6);
359 mCurrentLevel = 2;
363 if (M2_gbTrace >= 1)
364 {
365 std::cout << "non-minimal betti: " << std::endl;
366 mBettiNonminimal.output();
367 }
368 //for (int i=0; i<mMinimalizeTODO.size(); i++)
369 // {
370 // auto a = mMinimalizeTODO[i];
371 // std::cout << "(" << a.first << "," << a.second << ") ";
372 // }
373 // std::cout << std::endl;
374 }
375 break;
376 case Matrices:
377 if (M2_gbTrace >= 1)
378 std::cout << "start_computation: entering matrices(" << mSlantedDegree << ", " << mCurrentLevel << ")" << std::endl;
379 if (stop.always_stop) return;
380
382 {
383 mCurrentLevel = 2;
385 if (mSlantedDegree > top_slanted_degree)
386 {
387 if (M2_gbTrace >= 1)
389#if 0
391#endif
392 timeA = timer();
393 for (auto it=mMinimalizeTODO.cbegin(); it != mMinimalizeTODO.cend(); ++it)
394 {
395 int rk = rank(it->first, it->second);
396 mBettiMinimal.entry(it->first, it->second) -= rk;
397 mBettiMinimal.entry(it->first+1, it->second-1) -= rk;
398 }
399 timeB = timer();
400 timeComputeRanks += seconds(timeB-timeA);
401 mState = Done;
402 if (M2_gbTrace >= 1)
403 mBettiMinimal.output();
404 break;
405 }
406 // if (stop.stop_after_degree and mSlantedDegree > stop.degree_limit->array[0])
407 // return;
408 }
409 if (M2_gbTrace >= 2)
410 {
411 std::cout << "construct(" << mSlantedDegree << ", " << mCurrentLevel << ")..." << std::endl;
412 }
414 if (M2_gbTrace >= 2)
415 std::cout << "done" << std::endl;
418 break;
419 case Done:
420 if (M2_gbTrace >= 1)
421 {
422 std::cout << "total time for make matrix: " << timeMakeMatrix << std::endl;
423 std::cout << "total time for sort matrix: " << timeSortMatrix << std::endl;
424 std::cout << "total time for reorder matrix: " << timeReorderMatrix << std::endl;
425 std::cout << "total time for gauss matrix: " << timeGaussMatrix << std::endl;
426 std::cout << "total time for clear matrix: " << timeClearMatrix << std::endl;
427 std::cout << "total time for reset hash table: " << timeResetHashTable << std::endl;
428 std::cout << "total time for computing ranks: " << timeComputeRanks << std::endl;
429 }
430 return;
431 default:
432 break;
433 }
434 }
435#endif
436}
437
439{
440 if (type == 4)
441 {
442 computeFrame();
443 decltype(timer()) timeA, timeB;
444 timeA = timer();
446 timeB = timer();
447 timeComputeRanks += seconds(timeB - timeA);
448
449 return mBettiMinimal.getBetti();
450 }
451 if (type == 0 or type == 1) return getBettiFrame();
452 if (type == 5) return mComputationStatus.getBetti();
453
454 ERROR("betti display not implemented yet");
455 return nullptr;
456}
457
459{
462 if (mCurrentLevel == 2)
463 {
464 mState = Frame;
465 }
466}
467
471{
472 PreElement* vp = mPreElements.allocate();
473 vp->vp = mVarpowers.reserve(mMaxVPSize);
474 monoid().quotient_as_vp(m1, m, vp->vp);
475 vp->degree = monoid().degree_of_vp(vp->vp);
476 int len = static_cast<int>(res_varpower_monomials::length(vp->vp));
477 mVarpowers.intern(len);
478 return vp;
479}
482 component_index elem)
483{
486 // Returns the number of elements added
487 res_packed_monomial m = monomial(lev, elem);
488 std::vector<PreElement*> elements;
489 if (ring().isSkewCommutative())
490 {
491 auto skewvars = new int[ring().monoid().n_vars()];
492 int a = ring().monoid().skew_vars(ring().skewInfo(), m, skewvars);
493 // std::cout << "adding " << a << " syz from skew" << std::endl;
494 for (int i = 0; i < a; ++i)
495 {
496 PreElement* vp = mPreElements.allocate();
497 vp->vp = mVarpowers.reserve(mMaxVPSize);
498 monoid().variable_as_vp(skewvars[i], vp->vp);
499 vp->degree = monoid().degree_of_vp(vp->vp);
500 int len = static_cast<int>(res_varpower_monomials::length(vp->vp));
501 mVarpowers.intern(len);
502
503 elements.push_back(vp);
504 }
505 delete[] skewvars;
506 }
507 for (component_index i = begin; i < elem; i++)
508 elements.push_back(createQuotientElement(monomial(lev, i), m));
510 MonomialLookupTable montab(monoid().n_vars());
511
512#if 0
513 std::cout << " #pre elements = " << elements.size() << std::endl;
514 for (auto i=elements.begin(); i != elements.end(); ++i)
515 {
516 varpower_monomials::elem_text_out(stdout, (*i)->vp);
517 fprintf(stdout, "\n");
518 }
519#endif
520 PreElementSorter C;
521 std::stable_sort(elements.begin(), elements.end(), C);
522
523 component_index n_elems = 0;
524 for (auto i = elements.begin(); i != elements.end(); ++i)
525 {
526 int32_t not_used;
527 bool inideal = montab.find_one_divisor_vp(0, (*i)->vp, not_used);
528 if (inideal) continue;
529 // Now we create a res_packed_monomial, and insert it into 'lev+1'
530 montab.insert_minimal_vp(0, (*i)->vp, 0);
531 res_packed_monomial monom =
532 monomialBlock().allocate(monoid().max_monomial_size());
533 monoid().from_varpower_monomial((*i)->vp, elem, monom);
534 // Now insert it into the frame
536 monom,
537 (*i)->degree + degree(currentLevel() - 1,
538 monoid().get_component(monom)));
539 n_elems++;
540 }
541 // std::cout << " returns " << n_elems << std::endl;
542 return n_elems;
543}
544
546{
547 if (currentLevel() == 1) return 0;
548 if (currentLevel() >= mFrame.mLevels.size()) return 0;
549 // std::cout << "computeNextLevel: level = " << currentLevel() << std::endl;
550 // loop through all the elements at level currentLevel()-2
551 int level0 = currentLevel() - 2;
552 int level1 = level0 + 1;
553 component_index n_elems_added = 0;
554 for (auto i = level(level0).begin(); i != level(level0).end(); ++i)
555 {
556 component_index begin = (*i).mBegin;
557 component_index end = (*i).mEnd;
558 for (component_index i = begin; i < end; ++i)
559 {
560 auto& elem = level(level1)[i];
561 elem.mBegin = n_elems_added;
562 n_elems_added += computeIdealQuotient(level1, begin, i);
563 elem.mEnd = n_elems_added;
564 }
565 }
568
569 return n_elems_added;
570}
571
573{
574 auto& myframe = level(lev);
575 auto& myorder = schreyerOrder(lev);
576 myorder.mTieBreaker.resize(myframe.size());
577 // std::cout << "setSchreyerOrder: entering, lev=" << lev << ", nelems=" <<
578 // myframe.size() << std::endl;
579 if (lev == 0)
580 {
581 for (component_index i = 0; i < myorder.mTieBreaker.size(); i++)
582 myorder.mTieBreaker[i] = i;
583 return;
584 }
585
586 auto& prevorder = schreyerOrder(lev - 1);
587 long* tiebreakers = new long[myframe.size()];
588
589 auto n_frame_elems = myframe.size();
590 for (component_index i = 0; i < n_frame_elems; i++)
591 {
592 component_index comp = monoid().get_component(myframe[i].mMonom);
593 tiebreakers[i] = i + n_frame_elems * prevorder.mTieBreaker[comp];
594 }
595 std::stable_sort(tiebreakers, tiebreakers + n_frame_elems);
596
597 for (component_index i = 0; i < n_frame_elems; i++)
598 {
599 myorder.mTieBreaker[tiebreakers[i] % n_frame_elems] = i;
600 }
601 delete[] tiebreakers;
602 // std::cout << " setSchreyerOrder: exiting, lev=" << lev << std::endl;
603}
604
606{
607 assert(lev >= 1); // Should not be called with lev==0.
608 // if lev >= 2, then level(lev-1)[comp].(mBegin,mEnd) is set separately.
609 auto& myframe = level(lev);
610 long idx = myframe.size();
611 myframe.emplace_back(FrameElement(monom, degree));
612 auto& myelem = myframe[idx];
613 myelem.mSyzygy.coeffs = vectorArithmetic().allocateElementArray();
614 // The rest of this code simply sets the total monomial for the Schreyer order
615 // and should be moved out of here. (MES 3 Feb 2016)
616 auto& myorder = schreyerOrder(lev);
617 auto myTotalMonom = monomialBlock().allocate(monoid().max_monomial_size());
618 auto& prevorder = schreyerOrder(lev - 1);
619 component_index comp = monoid().get_component(myelem.mMonom);
621 myelem.mMonom, prevorder.mTotalMonom[comp], myTotalMonom);
622 monoid().set_component(monoid().get_component(prevorder.mTotalMonom[comp]),
623 myTotalMonom);
624 myorder.mTotalMonom.push_back(myTotalMonom);
625}
626
628 int degree,
629 int maxdeglevel0)
630{
631 (void) maxdeglevel0;
632 auto& myframe = level(0);
633 long idx = myframe.size();
634 myframe.emplace_back(FrameElement(monom, degree));
635 auto& myelem = myframe[idx];
636
637 auto& myorder = schreyerOrder(0);
638 auto myTotalMonom =
639 monomialBlock().allocate(monoid().monomial_size(myelem.mMonom));
640 // Create the total monomial. It is monom * (firstvar)^(maxdeglevel0-degree)
641 monoid().copy(myelem.mMonom, myTotalMonom);
642 myorder.mTotalMonom.push_back(myTotalMonom);
643}
645 int deg,
646 ResPolynomial& syzygy)
647{
648 insertBasic(1, monom, deg); // deg is the actual degree of this element.
649 component_index comp = monoid().get_component(monom);
650 auto last = static_cast<component_index>(level(1).size());
651 auto& p = level(0)[comp];
652 if (p.mBegin == -1) p.mBegin = last - 1;
653 p.mEnd = last;
654 if (!check_poly(ring(), syzygy, schreyerOrder(0)))
655 {
656 if (M2_gbTrace >= 1)
657 {
658 std::cout
659 << "Error: expected terms of polynomial to be in order, in poly#"
660 << last << ": ";
661 display_poly(std::cout, ring(), syzygy);
662 std::cout << std::endl;
663 }
664 return false;
665 }
666 std::swap(level(1)[level(1).size() - 1].mSyzygy, syzygy);
667 return true;
668}
669
671{
672 if (lev == 0) return true;
673 bool result = true;
674 auto& mylevel = level(lev);
675 auto& myorder = schreyerOrder(lev - 1);
676 int which = 0;
677 for (auto i = mylevel.cbegin(); i != mylevel.cend(); ++i, ++which)
678 {
679 if (!check_poly(ring(), i->mSyzygy, myorder))
680 {
681 std::cout << "Error: terms of polynomial at level " << lev
682 << " location " << which << " not in order" << std::endl;
683 std::cout << " poly = ";
684 display_poly(std::cout, ring(), i->mSyzygy);
685 std::cout << std::endl;
686 result = false;
687 }
688 }
689 return result;
690}
692{
693 std::cout
694 << "checking that all input and constructed polynomials are in order...";
695 bool result = true;
696 for (auto i = 1; i < maxLevel(); ++i)
697 if (!debugCheckOrder(i)) result = false;
698 if (result) std::cout << "ok" << std::endl;
699 return result;
700}
701
703{
704 long result = mMonomialSpace.memoryUsage();
705 for (int i = 0; i < mFrame.mLevels.size(); i++)
706 {
707 result += level(i).capacity() * sizeof(FrameElement);
708 }
709 return result;
710}
711
713{
714 std::cout << "Frame memory usage" << std::endl;
715 // widths: level: 6, #elems: 8, used: 6, allocated: 11
716 std::cout << " level"
717 << " #elems"
718 << " used"
719 << " allocated"
720 << " nterms"
721 << " poly"
722 << " polalloc" << std::endl;
723 long alloc = 0;
724 long used = 0;
725 long nelems = 0;
726 long poly_used = 0;
727 long poly_alloc = 0;
728 long poly_nterms = 0;
729 long poly_used_level = 0;
730 long poly_alloc_level = 0;
731 long poly_nterms_level = 0;
732 for (int i = 0; i < mFrame.mLevels.size(); i++)
733 {
734 long nelems_level = level(i).size();
735 if (nelems_level == 0) continue;
736 long used_level = nelems_level * sizeof(FrameElement);
737 long alloc_level = level(i).capacity() * sizeof(FrameElement);
738 poly_nterms_level = 0;
739 poly_used_level = 0;
740 poly_alloc_level = 0;
741 for (int j = 0; j < nelems_level; j++)
742 {
743 ring().memUsage(level(i)[j].mSyzygy,
744 poly_nterms_level,
745 poly_used_level,
746 poly_alloc_level);
747 }
748 poly_nterms += poly_nterms_level;
749 poly_used += poly_used_level;
750 poly_alloc += poly_alloc_level;
751 std::cout << std::setw(6) << i << " " << std::setw(8) << nelems_level
752 << " " << std::setw(6) << used_level << " " << std::setw(11)
753 << alloc_level << " " << std::setw(10) << poly_nterms_level
754 << " " << std::setw(10) << poly_used_level << " "
755 << std::setw(10) << poly_alloc_level << std::endl;
756 nelems += nelems_level;
757 used += used_level;
758 alloc += alloc_level;
759 }
760 std::cout << " all"
761 << " " << std::setw(8) << nelems << " " << std::setw(6) << used
762 << " " << std::setw(11) << alloc << " " << std::setw(10)
763 << poly_nterms << " " << std::setw(10) << poly_used << " "
764 << std::setw(10) << poly_alloc << std::endl;
765
766 long monomSpace = mMonomialSpace.memoryUsage();
767 long monomUsed =
768 nelems * monoid().max_monomial_size() * sizeof(monomial_word);
769 std::cout << "monomials " << std::setw(6) << monomUsed << " "
770 << std::setw(11) << monomSpace << std::endl;
771 std::cout << "total mem " << std::setw(6)
772 << (used + monomUsed + poly_used) << " " << std::setw(11)
773 << (alloc + monomSpace + poly_alloc) << std::endl;
774}
775
776void SchreyerFrame::show(int len) const
777{
778 std::cout << "#levels=" << mFrame.mLevels.size()
779 << " currentLevel=" << currentLevel() << std::endl;
780 for (int i = 0; i < mFrame.mLevels.size(); i++)
781 {
782 auto& myframe = level(i);
783 auto& myorder = schreyerOrder(i);
784 if (myframe.size() == 0) continue;
785 std::cout << "--- level " << i << " ------" << std::endl;
786 for (int j = 0; j < myframe.size(); j++)
787 {
788 std::cout << " " << j << " " << myframe[j].mDegree << " ("
789 << myframe[j].mBegin << "," << myframe[j].mEnd << ") "
790 << std::flush;
791 if (myframe[j].mSyzygy.coeffs.isNull())
792 std::cout << "coeffs=null " << std::flush;
793 std::cout << "(size:" << myframe[j].mSyzygy.len << ") [";
794 monoid().showAlpha(myorder.mTotalMonom[j]);
795 std::cout << " " << myorder.mTieBreaker[j] << "] ";
796 if (len == 0 or myframe[j].mSyzygy.len == 0)
797 monoid().showAlpha(myframe[j].mMonom);
798 else
799 {
800 display_poly(std::cout, ring(), myframe[j].mSyzygy);
801 }
802 std::cout << std::endl;
803 }
804 }
806}
807
808void SchreyerFrame::getBounds(int& loDegree, int& hiDegree, int& length) const
809{
810 if (mFrame.mLevels.size() == 0 or mFrame.mLevels[0].mElements.size() == 0)
811 {
812 loDegree = 0;
813 hiDegree = -1;
814 length = 0;
815 return;
816 }
817 length = 0;
818 auto& lev0 = level(0);
819 loDegree = hiDegree = static_cast<int>(lev0[0].mDegree);
820 for (int lev = 0; lev < mFrame.mLevels.size(); lev++)
821 {
822 auto& myframe = level(lev);
823 if (myframe.size() == 0) return;
824 length = lev;
825 for (auto p = myframe.begin(); p != myframe.end(); ++p)
826 {
827 int deg = p->mDegree;
828 deg -= lev; // slanted degree
829 if (deg < loDegree) loDegree = deg;
830 if (deg > hiDegree) hiDegree = deg;
831 }
832 }
833 // show();
834}
835
837{
838 int lo, hi, len;
839 getBounds(lo, hi, len);
840 // std::cout << "bounds: lo=" << lo << " hi=" << hi << " len=" << len <<
841 // std::endl;
842 mBettiNonminimal = BettiDisplay(lo, hi, len);
843 mBettiMinimal = BettiDisplay(lo, hi, len);
845
846 for (int lev = 0; lev <= len; lev++)
847 {
848 auto& myframe = level(lev);
849 for (auto p = myframe.begin(); p != myframe.end(); ++p)
850 {
851 int deg = p->mDegree; // this is actual degree, not slanted degree
852 mBettiNonminimal.entry(deg - lev, lev)++;
853 mBettiMinimal.entry(deg - lev, lev)++;
854 }
855 }
856
857 // std::cout << "--- minimal betti set ---\n";
858 // mBettiMinimal.output();
859#if 0
860 // Now set the todo list of pairs (degree, level) for minimalization.
861 for (int slanted_degree = lo; slanted_degree < hi; slanted_degree++)
862 {
863 for (int lev = 1; lev <= maxLevel()-1; lev++)
864 {
865 if (mBettiNonminimal.entry(slanted_degree, lev) > 0 and mBettiNonminimal.entry(slanted_degree+1, lev-1) > 0)
866 {
867 mMinimalizeTODO.push_back(std::make_pair(slanted_degree, lev));
868 }
869
870 }
871 }
872#endif
873 // Meaning: 0: no syzygies in that (degree,lev)
874 // 1: there are some, but syzygies have not been constructed yet
875 // 2: syzygies have been constructed
876 // 3: syzygies have been constructed AND rank from (deg,lev) to
877 // (deg+1,lev-1) has been
878 // computed, and the ranks taken into account in mMinimalBetti.
879 for (int slanted_degree = lo; slanted_degree <= hi; slanted_degree++)
880 {
881 if (len >= 0)
882 {
883 if (mBettiNonminimal.entry(slanted_degree, 0) == 0)
884 mComputationStatus.entry(slanted_degree, 0) = 0;
885 else
886 mComputationStatus.entry(slanted_degree, 0) = 3;
887 }
888
889 if (len >= 1)
890 {
891 if (mBettiNonminimal.entry(slanted_degree, 1) == 0)
892 mComputationStatus.entry(slanted_degree, 1) = 0;
893 else
894 mComputationStatus.entry(slanted_degree, 1) = 2;
895 }
896
897 for (int lev = 2; lev <= maxLevel(); lev++)
898 {
899 if ((lev > len) or mBettiNonminimal.entry(slanted_degree, lev) == 0)
900 mComputationStatus.entry(slanted_degree, lev) = 0;
901 else
902 mComputationStatus.entry(slanted_degree, lev) = 1;
903 }
904 }
905}
906
907void SchreyerFrame::computeSyzygies(int slanted_degree, int maxlevel)
908{
909 // Compute everything up to this point
910 int toplevel = (maxlevel < maxLevel() ? maxlevel : maxLevel());
911 for (int deg = mLoSlantedDegree; deg <= slanted_degree; deg++)
912 for (int lev = 2; lev <= toplevel; lev++)
913 {
914 fillinSyzygies(deg, lev);
915 }
916 // show(-1);
917}
918void SchreyerFrame::computeRanks(int slanted_degree, int maxlevel)
919{
920 // Compute all needed ranks to get the minimal Betti numbers in the range
921 // deg <= slanted_degree, lev <=maxlevel.
922 // This means: we need to compute ranks to level maxlevel+1 (or largest that
923 // exists)
924 // in degrees <= slanted_degree, EXCEPT we don't need to compute at
925 // (slanted_degree,maxlevel+1).
926 int toplevel = (maxlevel < maxLevel() ? maxlevel - 1 : mMaxLength);
927 for (int deg = mLoSlantedDegree; deg <= slanted_degree; deg++)
928 for (int lev = 1; lev <= toplevel; lev++) computeRank(deg, lev);
929}
930void SchreyerFrame::fillinSyzygies(int slanted_deg, int lev)
931{
932 // Fill in syzygies of slanted degree mSlantedDegree, at level mCurrentLevel =
933 // 2.
934 // Assumption/prereq:
935 // Compute the matrix at this level, where lev >= 2. (lev=0,1 have already
936 // been filled in).
937 // Prereqs: fillin(i,lev-1) has been called, for all i <= slanted_degree.
938 // WARNING: this is not currently checked or remembered.
939
940 int& status = mComputationStatus.entry(slanted_deg, lev);
941 if (status != 1) return;
942
943 if (M2_gbTrace >= 2)
944 {
945// std::cout << "construct(" << slanted_deg << ", " << lev << ")"
946// << std::endl;
947 }
948
949 // experimenting whether building/destroying local computers
950 // are expensive
951 F4Res thisComputer {*this};
952 thisComputer.construct(lev, slanted_deg + lev);
953 //mComputer->construct(lev, slanted_deg + lev);
954
955 status = 2;
956
957 if (M2_gbTrace >= 2)
958 {
959 //std::cout << "done" << std::endl;
960 //std::cout << "#additions so far: " << vectorArithmetic().getNumAdditions()
961 // << std::endl;
962 }
963}
964void SchreyerFrame::computeRank(int slanted_degree, int lev)
965{
966 // std::cout << "computeRank(" << slanted_degree << "," << lev << ")" <<
967 // std::endl;
968 int& status = mComputationStatus.entry(slanted_degree, lev);
969 if (status == 0) return; // Nothing here
970 if (status == 1)
971 {
972 fillinSyzygies(slanted_degree, lev);
973 }
974 if (status == 3) return; // already done
975 int rk = rank(slanted_degree, lev);
976 if (rk > 0)
977 {
978 mBettiMinimal.entry(slanted_degree, lev) -= rk;
979 if (slanted_degree <= mHiSlantedDegree and lev > 0)
980 mBettiMinimal.entry(slanted_degree + 1, lev - 1) -= rk;
981
982 // std::cout << "--- minimal betti after computeRank: " << slanted_degree << " " << lev << std::endl;
983 // mBettiMinimal.output();
984 }
985 status = 3;
986}
987
989{
990 int lo, hi, len;
991 getBounds(lo, hi, len);
992 // std::cout << "bounds: lo=" << lo << " hi=" << hi << " len=" << len <<
993 // std::endl;
994 BettiDisplay B(lo, hi, len);
995 // now set B
996
997 for (int lev = 0; lev <= len; lev++)
998 {
999 auto& myframe = level(lev);
1000 for (auto p = myframe.begin(); p != myframe.end(); ++p)
1001 {
1002 int deg = p->mDegree; // this is actual degree, not slanted degree
1003 B.entry(deg - lev, lev)++;
1004 }
1005 }
1006
1007 return B.getBetti();
1008}
1009
1010// local Variables:
1011// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
1012// indent-tabs-mode: nil
1013// End:
M2_arrayint getBetti() const
Definition betti.cpp:82
void resize(int new_lo_degree, int new_hi_degree, int new_length)
Definition betti.cpp:58
int & entry(int deg, int lev)
Definition betti.cpp:71
Engine-side Betti table: a (degree, homological level) rectangle of integers.
Definition betti.hpp:60
static int compare(ConstExponents a, ConstExponents b)
static void elem_text_out(buffer &o, ConstExponents m, bool p_one=true)
static const Exponent length(ConstExponents m)
void insert_minimal_vp(long comp, const_varpower_monomial m, Key k)
bool find_one_divisor_vp(long comp, const_varpower_monomial m, Key &result_k) const
void construct(int lev, int degree)
Definition res-f4.cpp:640
T * allocate(int len=1)
int max_monomial_size() const
component_index get_component(res_const_packed_monomial m) const
void copy(res_const_packed_monomial src, res_packed_monomial target) const
void showAlpha(res_const_packed_monomial m) const
void set_component(component_index component, res_packed_monomial m) const
int skew_vars(const SkewMultiplication *skew, res_const_packed_monomial m, int *skewvars) const
void from_varpower_monomial(res_const_varpower_monomial m, component_index comp, res_packed_monomial result) const
void unchecked_mult(res_const_packed_monomial m, res_const_packed_monomial n, res_packed_monomial result) const
void quotient_as_vp(res_const_packed_monomial a, res_const_packed_monomial b, res_varpower_monomial result) const
void variable_as_vp(int v, res_varpower_monomial result) const
int degree_of_vp(res_const_varpower_monomial a) const
const ResMonoid & monoid() const
void memUsage(const ResPolynomial &f, long &nterms, long &bytes_used, long &bytes_alloc) const
The polynomial-ring view the F4 resolution engine reduces against: coefficient arithmetic plus the en...
static long npoly_destructor
Polynomial type used by the F4 resolution engine: parallel coefficient vector and concatenated monomi...
int degree(int lev, component_index component) const
std::vector< std::pair< int, int > > mMinimalizeTODO
void computeSyzygies(int slanted_degree, int maxlevel)
void computeRanks(int slanted_degree, int maxlevel)
SchreyerFrame(const ResPolyRing &R, int max_level, int numThreads, bool parallelizeByDegree)
void computeRank(int slanted_degree, int lev)
SchreyerFrameTypes::FrameElement FrameElement
BettiDisplay minimalBettiNumbers(bool stop_after_degree, int top_slanted_degree, int length_limit)
void setSchreyerOrder(int lev)
long memoryUsage() const
BettiDisplay mBettiMinimal
int rank(int slanted_degree, int lev)
enum SchreyerFrame::@107076371201376153077324375251043314133302145334 mState
M2_arrayint getBettiFrame() const
void insertLevelZero(res_packed_monomial monom, int degree, int maxdeglevel0)
component_index computeNextLevel()
const ResMonoid & monoid() const
void show(int len) const
ResMemoryBlock< res_monomial_word > & monomialBlock()
component_index computeIdealQuotient(int lev, component_index begin, component_index elem)
bool insertLevelOne(res_packed_monomial monom, int degree, ResPolynomial &syzygy)
ResMemoryBlock< PreElement > mPreElements
ResMemoryBlock< res_varpower_word > mVarpowers
void start_computation(StopConditions &stop)
BettiDisplay mComputationStatus
M2_arrayint getBetti(int type)
SchreyerFrameTypes::PreElement PreElement
std::vector< FrameElement > & level(int lev)
void insertBasic(int lev, res_packed_monomial monom, int degree)
const ResPolyRing & ring() const
PreElement * createQuotientElement(res_packed_monomial m1, res_packed_monomial m)
const ResPolyRing & mRing
const VectorArithmetic & vectorArithmetic() const
ResMemoryBlock< res_monomial_word > mMonomialSpace
void getBounds(int &loDegree, int &hiDegree, int &length) const
void showMemoryUsage() const
BettiDisplay mBettiNonminimal
bool debugCheckOrderAll() const
ResSchreyerOrder & schreyerOrder(int lev)
void fillinSyzygies(int slanted_deg, int lev)
std::unique_ptr< F4Res > mComputer
bool debugCheckOrder(int lev) const
ElementArray allocateElementArray(ComponentIndex nelems) const
Create a coefficient vector with room for nelems coefficients.
ComputationStatusCode / StopConditions / StrategyValues / Algorithms / gbTraceValues — engine-to-inte...
Engine error-reporting primitives: ERROR, INTERNAL_ERROR, error, error_message.
F4MonomialLookupTableT< int32_t > MonomialLookupTable
Definition f4-types.hpp:357
#define monomial
Definition gb-toric.cpp:11
static int compare(const vecterm *t, const vecterm *s)
Definition geovec.hpp:112
int p
const int ERROR
Definition m2-mem.cpp:55
VALGRIND_MAKE_MEM_DEFINED & result(result)
int M2_gbTrace
Definition m2-types.cpp:52
long monomial_word
Definition moninfo.hpp:77
MonomialInfo — F4's packed_monomial encoding plus operations.
void swap(mpfr::mpreal &x, mpfr::mpreal &y)
Definition mpreal.h:3244
ResF4MonomialLookupTableT<Key> — tree-structured leading-term index for the F4 resolution.
F4Res — F4-style matrix-reduction worker over a SchreyerFrame.
myword component_index
res_monomial_word * res_packed_monomial
Typed-monomial vocabulary shared by ResMonoid, ResPolyRing, SchreyerFrame, and F4Res.
bool check_poly(const ResPolyRing &R, const ResPolynomial &f, const ResSchreyerOrder &ord)
void display_poly(std::ostream &o, const ResPolyRing &R, const ResPolynomial &f)
SchreyerFrame — in-progress representation of a free resolution organised by (level,...
void makeDependencyGraph(int nlevels, int nslanted_degrees)
TermIterator< Nterm > begin(Nterm *ptr)
Definition ringelem.cpp:4
TermIterator< Nterm > end(Nterm *)
Definition ringelem.cpp:5
The full frame: a vector of Levels indexed by homological degree.
M2_bool always_stop
Definition computation.h:91
M2_bool stop_after_degree
Definition computation.h:92
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
const int GT
Definition style.hpp:41
const int LT
Definition style.hpp:39
Engine-wide stylistic constants: LT / EQ / GT codes, INTSIZE, GEOHEAP_SIZE.
std::chrono::steady_clock::time_point timer()
Definition timing.hpp:35
double seconds(DurationType time_diff)
Definition timing.hpp:59
Inline std::chrono::steady_clock wrappers and elapsed-time conversion helpers.