1 /*
2 * Normaliz
3 * Copyright (C) 2007-2019 Winfried Bruns, Bogdan Ichim, Christof Soeger
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * As an exception, when this program is distributed through (i) the App Store
18 * by Apple Inc.; (ii) the Mac App Store by Apple Inc.; or (iii) Google Play
19 * by Google Inc., then that store may impose any digital rights management,
20 * device limits and/or redistribution restrictions that are required by its
21 * terms of service.
22 */
23
24 //---------------------------------------------------------------------------
25
26 #include <cstdlib>
27 #include <set>
28 #include <map>
29 #include <iostream>
30 #include <string>
31 #include <algorithm>
32 #include <chrono>
33 #include <deque>
34 #include <cmath>
35 #include <iomanip>
36 #include <fstream>
37
38 #include <sys/time.h>
39
40 #include "libnormaliz/cone.h"
41 #include "libnormaliz/full_cone.h"
42 #include "libnormaliz/project_and_lift.h"
43 #include "libnormaliz/vector_operations.h"
44 #include "libnormaliz/list_and_map_operations.h"
45 // #include "libnormaliz/map_operations.h"
46 #include "libnormaliz/integer.h"
47 #include "libnormaliz/sublattice_representation.h"
48 #include "libnormaliz/offload_handler.h"
49
50 //---------------------------------------------------------------------------
51
52 namespace libnormaliz {
53 using namespace std;
54
55
56
57 // clock_t pyrtime;
58
59 const size_t HollowTriBound = 20000000; // bound for the number of simplices computed in a pattern
60 // evaluated for hollow triangulation
61
62 const size_t EvalBoundTriang = 5000000; // if more than EvalBoundTriang simplices have been stored
63 // evaluation is started (whenever possible)
64
65 const size_t EvalBoundPyr = 500000; // the same for stored pyramids of level > 0
66
67 const size_t EvalBoundLevel0Pyr = 500000; // 1000000; // the same for stored level 0 pyramids
68
69 const int largePyramidFactor =
70 20; // pyramid is large if largePyramidFactor*Comparisons[Pyramid_key.size()-dim] > old_nr_supp_hyps
71
72 const int SuppHypRecursionFactor = 320000; // pyramids for supphyps formed if Pos*Neg > ...
73
74 const size_t RAM_Size = 1000000000; // we assume that there is at least 1 GB of RAM
75
76 const long GMP_time_factor = 10; // factor by which GMP arithmetic differs from long long
77 const long renf_time_factor = 20; // N the same for renf
78 const long renf_time_factor_pyr = 5; // used for control of pyramid building without triangulation
79
80 // const long ticks_norm_quot = 155; // approximately the quotient of the ticks row/cont in A553 with GMP
81
82 //-------------------------------------------------------------------------
83 // Hedre to avoid a probem with certain compikers
84
85 void integrate(SignedDec<mpz_class>& SD, const bool do_virt_mult);
86
87
88 template <typename Integer>
ComputeIntegral(const bool do_virt)89 bool SignedDec<Integer>::ComputeIntegral(const bool do_virt){
90
91 assert(false);
92 return true;
93 }
94
95 template<>
ComputeIntegral(const bool do_virt)96 bool SignedDec<mpz_class>::ComputeIntegral(const bool do_virt){
97
98 if(decimal_digits > 0)
99 approximate = true;
100 approx_denominator =1;
101 if(approximate){
102 for(long i= 0; i< decimal_digits; ++i)
103 approx_denominator *= 10;
104 }
105
106 if(verbose)
107 verboseOutput() << "Generic " << Generic;
108
109 #ifdef NMZ_COCOA
110 integrate(*this, do_virt);
111 #endif
112 return true;
113 }
114 //-------------------------------------------------------------------------
115
116 template <typename Integer>
compute_automorphisms(size_t nr_special_gens)117 void Full_Cone<Integer>::compute_automorphisms(size_t nr_special_gens) {
118 if (!do_automorphisms || isComputed(ConeProperty::Automorphisms)) {
119 return;
120 }
121
122 // bool only_from_god_father = false; // not used at present
123 // if (do_integrally_closed && descent_level > 0) // we can only work with automprphisms induced by God_Father
124 // only_from_god_father = true;
125
126 get_supphyps_from_copy(true); // of course only if they haven't been computed
127 extreme_rays_and_deg1_check(); // ditto
128
129 if (!isComputed(ConeProperty::SupportHyperplanes) || !isComputed(ConeProperty::ExtremeRays)) {
130 throw FatalException("Trying to compute austomorphism group without sufficient data! THIS SHOULD NOT HAPPEN!");
131 }
132
133 if (!inhomogeneous && quality_of_automorphisms == AutomParam::rational && !isComputed(ConeProperty::Grading))
134 throw NotComputableException("Rational austomorphism group only computable for polytopes");
135
136 if (verbose)
137 verboseOutput() << "Computing automorphism group" << endl;
138
139 Matrix<Integer> SpecialLinForms(0, dim);
140 if (inhomogeneous) {
141 SpecialLinForms.append(Truncation);
142 }
143 if (isComputed(ConeProperty::Grading) && Grading.size() > 0) {
144 SpecialLinForms.append(Grading);
145 }
146
147 Automs = AutomorphismGroup<Integer>(Generators.submatrix(Extreme_Rays_Ind), Support_Hyperplanes, SpecialLinForms);
148
149 bool success = Automs.compute(quality_of_automorphisms);
150
151 if (!success) {
152 /* if (only_from_god_father) {
153 if (verbose)
154 verboseOutput() << "Coputation of automorphism group from extreme rays failed" << endl;
155 return;
156 } */
157 if (verbose)
158 verboseOutput() << "Coputation of integral automorphism group from extreme rays failed, using Hilbert basis" << endl;
159 if (!isComputed(ConeProperty::HilbertBasis)) {
160 if (verbose)
161 verboseOutput() << "Must compute Hilbert basis first, making copy" << endl;
162 Full_Cone<Integer> Copy(Generators);
163 Copy.do_Hilbert_basis = true;
164 Copy.keep_order = true;
165 Copy.verbose = verbose;
166 Copy.Support_Hyperplanes = Support_Hyperplanes;
167 Copy.nrSupport_Hyperplanes = nrSupport_Hyperplanes;
168 Copy.setComputed(ConeProperty::SupportHyperplanes);
169 Copy.Extreme_Rays_Ind = Extreme_Rays_Ind;
170 Copy.setComputed(ConeProperty::ExtremeRays);
171 Copy.compute();
172 if (Copy.isComputed(ConeProperty::HilbertBasis)) {
173 Hilbert_Basis.clear();
174 Hilbert_Basis.splice(Hilbert_Basis.begin(), Copy.Hilbert_Basis);
175 setComputed(ConeProperty::HilbertBasis);
176 do_Hilbert_basis = false;
177 }
178 // do_Hilbert_basis=true; <-- makes no sense
179 }
180
181 Automs = AutomorphismGroup<Integer>(Generators.submatrix(Extreme_Rays_Ind), Support_Hyperplanes, SpecialLinForms);
182
183 Automs.addComputationGens(Matrix<Integer>(Hilbert_Basis));
184 success = Automs.compute(AutomParam::integral);
185 }
186 assert(success == true);
187 /* if (only_from_god_father) {
188 if (!check_extension_to_god_father())
189 return;
190 }*/
191 setComputed(ConeProperty::Automorphisms);
192 if (verbose)
193 verboseOutput() << Automs.getQualitiesString() << "automorphism group of order " << Automs.getOrder() << " done" << endl;
194 }
195
196 template <>
compute_automorphisms(size_t nr_special_gens)197 void Full_Cone<renf_elem_class>::compute_automorphisms(size_t nr_special_gens) {
198 if (!do_automorphisms || isComputed(ConeProperty::Automorphisms)) {
199 return;
200 }
201
202 get_supphyps_from_copy(true); // of course only if they haven't been computed
203 extreme_rays_and_deg1_check(); // ditto
204
205 if (!isComputed(ConeProperty::SupportHyperplanes) || !isComputed(ConeProperty::ExtremeRays)) {
206 throw FatalException("Trying to compute austomorphism group without sufficient data! THIS SHOULD NOT HAPPEN!");
207 return;
208 }
209
210 if (verbose)
211 verboseOutput() << "Computing automorphism group" << endl;
212
213 Matrix<renf_elem_class> HelpGen = Generators.submatrix(Extreme_Rays_Ind);
214 vector<renf_elem_class> HelpGrading;
215 if (!inhomogeneous) {
216 if (!isComputed(ConeProperty::Grading))
217 throw NotComputableException("For automorphisms of algebraic polyhedra input must define a polytope");
218 HelpGrading = Grading;
219 }
220 else {
221 HelpGrading = Truncation;
222 }
223
224 /*for(size_t i=0;i<HelpGen.nr_of_rows();++i){ // norm the extreme rays to vertices of polytope
225 renf_elem_class test=v_scalar_product(HelpGen[i],HelpGrading);
226 if(test==0)
227 throw NotComputableException("For automorphisms of algebraic polyhedra input must defime a polytope!");
228 v_scalar_division(HelpGen[i],test);
229 }*/
230
231 Matrix<renf_elem_class> SpecialLinForms(0, dim);
232 if (HelpGrading.size() > 0)
233 SpecialLinForms.append(HelpGrading);
234
235 Automs = AutomorphismGroup<renf_elem_class>(HelpGen, Support_Hyperplanes, SpecialLinForms);
236 Automs.compute(AutomParam::algebraic);
237
238 setComputed(ConeProperty::Automorphisms);
239 if (verbose)
240 verboseOutput() << Automs.getQualitiesString() << "automorphism group of order " << Automs.getOrder() << " done" << endl;
241 }
242
243 //---------------------------------------------------------------------------
244
245 /* debugging routine
246 template <typename Integer>
247 void Full_Cone<Integer>::check_facet(const FACETDATA<Integer>& Fac, const size_t& new_generator) const {
248 for (size_t jj = 0; jj < nr_gen; ++jj)
249 if (in_triang[jj] && v_scalar_product(Fac.Hyp, Generators[jj]) < 0) {
250 cerr << "Hyp negative on generator " << jj << endl;
251 assert(false);
252 }
253
254 vector<key_t> FacetKey;
255 for (size_t jj = 0; jj < nr_gen; ++jj) {
256 if (in_triang[jj] || jj == new_generator) {
257 if (Fac.GenInHyp[jj])
258 FacetKey.push_back(jj);
259 }
260 else {
261 if (Fac.GenInHyp[jj]) {
262 cerr << "in_triang error generator " << jj << endl;
263 assert(false);
264 }
265 }
266 }
267
268 if (Generators.rank_submatrix(FacetKey) < dim - 1) {
269 cerr << "Redundant hyperplane" << endl;
270 assert(false);
271 }
272
273 bool correct = true;
274 for (size_t jj = 0; jj < nr_gen; ++jj) {
275 if (in_triang[jj] && Fac.GenInHyp[jj] && v_scalar_product(Fac.Hyp, Generators[jj]) != 0) {
276 cerr << "Damned "
277 << " Index " << jj << endl;
278 correct = false;
279 }
280 if (in_triang[jj] && !Fac.GenInHyp[jj] && v_scalar_product(Fac.Hyp, Generators[jj]) == 0) {
281 cerr << "Damned 2"
282 << " Index " << jj << endl;
283 correct = false;
284 }
285 }
286 if (!correct) {
287 cerr << "--------------- ";
288 if (is_pyramid)
289 cerr << "pyr";
290 cerr << endl;
291 assert(false);
292 }
293 }
294 */
295 //---------------------------------------------------------------------------
296
297 template <typename Integer>
rank_time()298 chrono::nanoseconds Full_Cone<Integer>::rank_time() {
299 size_t nr_tests = 50;
300 /*
301 if(using_GMP<Integer>())
302 nr_tests/=GMP_time_factor;
303 if(using_renf<Integer>())
304 nr_tests/=renf_time_factor;*/
305 size_t nr_selected = min(3 * dim, nr_gen);
306
307 auto cl0 = chrono::high_resolution_clock::now();
308
309 #pragma omp parallel for
310 for (int kk = 0; kk < omp_get_max_threads(); ++kk) {
311 Matrix<Integer>& Test = Top_Cone->RankTest[kk];
312 for (size_t i = 0; i < nr_tests; ++i) {
313 vector<key_t> test_key;
314 for (size_t j = 0; j < nr_selected; ++j)
315 test_key.push_back(rand() % nr_gen);
316 Test.rank_submatrix(Generators, test_key);
317 }
318 }
319
320 auto cl1 = chrono::high_resolution_clock::now();
321
322 ticks_rank_per_row = (cl1 - cl0) / (nr_tests * nr_selected);
323
324 if (verbose)
325 verboseOutput() << "Per row " << ticks_rank_per_row.count() \
326 << " nanoseconds" << endl;
327
328 return ticks_rank_per_row;
329 }
330
331 template <typename Integer>
cmp_time()332 chrono::nanoseconds Full_Cone<Integer>::cmp_time() {
333 vector<list<dynamic_bitset>> Facets_0_1(omp_get_max_threads());
334
335 auto Fac = Facets.begin();
336 for (size_t i = 0; i < old_nr_supp_hyps; ++i, ++Fac) {
337 if (Fac->simplicial)
338 continue;
339 Facets_0_1[0].push_back(Fac->GenInHyp);
340 }
341 for (int i = 1; i < omp_get_max_threads(); ++i)
342 Facets_0_1[i] = Facets_0_1[0];
343
344 auto cl0 = chrono::high_resolution_clock::now();
345
346 #pragma omp parallel
347 {
348 #pragma omp for
349 for (int i = 0; i < omp_get_max_threads(); ++i) {
350 for (auto p = Facets_0_1[i].begin(); p != Facets_0_1[i].end(); ++p) {
351 /*bool contained=*/Facets.begin()->GenInHyp.is_subset_of(*p) && (*p) != (*Facets_0_1[i].begin()) &&
352 (*p) != (*Facets_0_1[i].end());
353 }
354 }
355 }
356
357 auto cl1 = chrono::high_resolution_clock::now();
358
359 ticks_comp_per_supphyp = (cl1 - cl0) / old_nr_supp_hyps;
360
361 if (verbose)
362 verboseOutput() << "Per comparison " \
363 << ticks_comp_per_supphyp.count() \
364 << " ticks (nanoseconds)" << endl;
365
366 return ticks_comp_per_supphyp;
367 }
368 //---------------------------------------------------------------------------
369
370 template <typename Integer>
set_zero_cone()371 void Full_Cone<Integer>::set_zero_cone() {
372 assert(dim == 0);
373
374 if (verbose) {
375 errorOutput() << "WARNING: Zero cone detected!" << endl;
376 }
377
378 // The basis change already is transforming to zero.
379 setComputed(ConeProperty::Sublattice);
380 setComputed(ConeProperty::Generators);
381 setComputed(ConeProperty::ExtremeRays);
382 Support_Hyperplanes = Matrix<Integer>(0);
383 setComputed(ConeProperty::SupportHyperplanes);
384 totalNrSimplices = 1;
385 setComputed(ConeProperty::TriangulationSize);
386 detSum = 1;
387 setComputed(ConeProperty::TriangulationDetSum);
388 SHORTSIMPLEX<Integer> empty_simpl;
389 empty_simpl.key = vector<key_t>();
390 empty_simpl.vol = 1;
391 Triangulation.push_back(empty_simpl);
392 setComputed(ConeProperty::Triangulation);
393 setComputed(ConeProperty::StanleyDec);
394 multiplicity = 1;
395 setComputed(ConeProperty::Multiplicity);
396 setComputed(ConeProperty::HilbertBasis);
397 if (!inhomogeneous)
398 setComputed(ConeProperty::Deg1Elements);
399
400 Hilbert_Series = HilbertSeries(vector<num_t>(1, 1), vector<denom_t>()); // 1/1
401 setComputed(ConeProperty::HilbertSeries);
402
403 if (!is_Computed.test(ConeProperty::Grading)) {
404 Grading = vector<Integer>(dim);
405 // GradingDenom = 1;
406 setComputed(ConeProperty::Grading);
407 }
408
409 pointed = true;
410 setComputed(ConeProperty::IsPointed);
411
412 deg1_extreme_rays = true;
413 setComputed(ConeProperty::IsDeg1ExtremeRays);
414
415 deg1_hilbert_basis = true;
416 setComputed(ConeProperty::IsDeg1HilbertBasis);
417
418 if (inhomogeneous) { // empty set of solutions
419 setComputed(ConeProperty::VerticesOfPolyhedron);
420 module_rank = 0;
421 setComputed(ConeProperty::ModuleRank);
422 setComputed(ConeProperty::ModuleGenerators);
423 level0_dim = 0;
424 setComputed(ConeProperty::RecessionRank);
425 }
426
427 if (!inhomogeneous) {
428 ClassGroup.resize(1, 0);
429 setComputed(ConeProperty::ClassGroup);
430 }
431
432 if (inhomogeneous || ExcludedFaces.nr_of_rows() != 0) {
433 multiplicity = 0;
434 setComputed(ConeProperty::Multiplicity);
435 Hilbert_Series.reset(); // 0/1
436 setComputed(ConeProperty::HilbertSeries);
437 }
438
439 if(do_automorphisms)
440 setComputed(ConeProperty::Automorphisms);
441 }
442
443 template <>
set_zero_cone()444 void Full_Cone<renf_elem_class>::set_zero_cone() {
445 assert(dim == 0);
446
447 if (verbose) {
448 verboseOutput() << "Zero cone detected!" << endl;
449 }
450
451 // The basis change already is transforming to zero.
452 setComputed(ConeProperty::Sublattice);
453 setComputed(ConeProperty::Generators);
454 setComputed(ConeProperty::ExtremeRays);
455 Support_Hyperplanes = Matrix<renf_elem_class>(0);
456 setComputed(ConeProperty::SupportHyperplanes);
457 totalNrSimplices = 1;
458 setComputed(ConeProperty::TriangulationSize);
459 detSum = 1;
460 SHORTSIMPLEX<renf_elem_class> empty_simpl;
461 empty_simpl.key = vector<key_t>();
462 empty_simpl.vol = 1;
463 Triangulation.push_back(empty_simpl);
464 setComputed(ConeProperty::Triangulation);
465
466 pointed = true;
467 setComputed(ConeProperty::IsPointed);
468
469 deg1_extreme_rays = true;
470 setComputed(ConeProperty::IsDeg1ExtremeRays);
471
472 if (inhomogeneous) { // empty set of solutions
473 setComputed(ConeProperty::VerticesOfPolyhedron);
474 module_rank = 0;
475 setComputed(ConeProperty::ModuleRank);
476 setComputed(ConeProperty::ModuleGenerators);
477 level0_dim = 0;
478 setComputed(ConeProperty::RecessionRank);
479 }
480
481 if(do_automorphisms)
482 setComputed(ConeProperty::Automorphisms);
483 }
484
485 //===========================================================
486
487 /* debuggin
488 template <typename Integer>
489 void Full_Cone<Integer>::check_simpliciality_hyperplane(const FACETDATA<Integer>& hyp) const {
490 size_t nr_gen_in_hyp = 0;
491 for (size_t i = 0; i < nr_gen; ++i)
492 if (in_triang[i] && hyp.GenInHyp.test(i))
493 nr_gen_in_hyp++;
494 if ((hyp.simplicial && nr_gen_in_hyp != dim - 2) || (!hyp.simplicial && nr_gen_in_hyp == dim - 2)) {
495 // NOTE: in_triang set at END of main loop in build_cone
496 errorOutput() << "Simplicial " << hyp.simplicial << " dim " << dim << " gen_in_hyp " << nr_gen_in_hyp << endl;
497 assert(false);
498 }
499 }
500 */
501
502 template <typename Integer>
set_simplicial(FACETDATA<Integer> & hyp)503 void Full_Cone<Integer>::set_simplicial(FACETDATA<Integer>& hyp) {
504 size_t nr_gen_in_hyp = 0;
505 for (size_t i = 0; i < nr_gen; ++i)
506 if (in_triang[i] && hyp.GenInHyp.test(i))
507 nr_gen_in_hyp++;
508 hyp.simplicial = (nr_gen_in_hyp == dim - 2);
509 }
510
511 template <typename Integer>
number_hyperplane(FACETDATA<Integer> & hyp,const size_t born_at,const size_t mother)512 void Full_Cone<Integer>::number_hyperplane(FACETDATA<Integer>& hyp, const size_t born_at, const size_t mother) {
513 // add identifying number, the birth day and the number of mother
514
515 if (don_t_add_hyperplanes)
516 return;
517
518 hyp.Mother = mother;
519 hyp.BornAt = born_at;
520 if (!multithreaded_pyramid) {
521 hyp.Ident = HypCounter[0];
522 HypCounter[0]++;
523 return;
524 }
525
526 int tn;
527 if (omp_get_level() == omp_start_level)
528 tn = 0;
529 else
530 tn = omp_get_ancestor_thread_num(omp_start_level + 1);
531 hyp.Ident = HypCounter[tn];
532 HypCounter[tn] += omp_get_max_threads();
533 // we nneed 64 bit for HypCounter[tn] in sufficiently big examples
534 assert(HypCounter[tn] % omp_get_max_threads() == (size_t) (tn + 1) % omp_get_max_threads());
535 }
536
537 //---------------------------------------------------------------------------
538
539 // used to decide if a hyperplane has the order vector on the positive side
540 // plus lex criterion
541 template <typename Integer>
is_hyperplane_included(FACETDATA<Integer> & hyp)542 bool Full_Cone<Integer>::is_hyperplane_included(FACETDATA<Integer>& hyp) {
543 if (!is_pyramid) { // in the topcone we always have ov_sp > 0
544 return true;
545 }
546 // check if it would be an excluded hyperplane
547 Integer ov_sp = v_scalar_product(hyp.Hyp, Order_Vector);
548 if (ov_sp > 0) {
549 return true;
550 }
551 else if (ov_sp == 0) {
552 for (size_t i = 0; i < dim; i++) {
553 if (hyp.Hyp[i] > 0) {
554 return true;
555 }
556 else if (hyp.Hyp[i] < 0) {
557 return false;
558 }
559 }
560 }
561 return false;
562 }
563
564 //---------------------------------------------------------------------------
565 /* not used, but kept
566 // produces the linear combination needed for a Fourier-Motzkin step
567 template <typename Integer>
568 vector<Integer> Full_Cone<Integer>::FM_comb(
569 const vector<Integer>& Pos, const Integer& PosVal, const vector<Integer>& Neg, const Integer& NegVal, bool extract_gcd) {
570 size_t k;
571 vector<Integer> NewFacet(dim);
572 for (k = 0; k < dim; k++) {
573 NewFacet[k] = PosVal * Neg[k] - NegVal * Pos[k];
574 if (!check_range(NewFacet[k]))
575 break;
576 }
577
578 if (k == dim) {
579 if (extract_gcd)
580 v_make_prime(NewFacet);
581 }
582 else {
583 #pragma omp atomic
584 GMP_hyp++;
585 vector<mpz_class> mpz_neg(dim), mpz_pos(dim), mpz_sum(dim);
586 convert(mpz_neg, Neg);
587 convert(mpz_pos, Pos);
588 mpz_class mpz_NV, mpz_PV;
589 mpz_NV = convertTo<mpz_class>(NegVal);
590 mpz_PV = convertTo<mpz_class>(PosVal);
591 for (k = 0; k < dim; k++)
592 mpz_sum[k] = mpz_PV * mpz_neg[k] - mpz_NV * mpz_pos[k];
593 if (extract_gcd)
594 v_make_prime(NewFacet);
595 v_make_prime(mpz_sum);
596 convert(NewFacet, mpz_sum);
597 }
598
599 return NewFacet;
600 }
601 */
602
603 //---------------------------------------------------------------------------
604
605 //---------------------------------------------------------------------------
606
607 template <typename Integer>
make_pyramid_for_last_generator(const FACETDATA<Integer> & Fac)608 void Full_Cone<Integer>::make_pyramid_for_last_generator(const FACETDATA<Integer>& Fac){
609
610 if(v_scalar_product(Fac.Hyp, Top_Cone->Generators[Top_Cone->top_last_to_be_inserted]) >= 0)
611 return;
612
613 vector<key_t> Pyramid_key;
614 Pyramid_key.push_back(Top_Cone->top_last_to_be_inserted);
615 for (size_t i = 0; i < Top_Cone-> nr_gen; i++) {
616 if (v_scalar_product(Fac.Hyp, Top_Cone->Generators[i]) == 0) {
617 Pyramid_key.push_back(i);
618 }
619 }
620
621 #pragma omp critical(STOREPYRAMIDS)
622 {
623 Top_Cone->Pyramids[0].push_back(Pyramid_key);
624 Top_Cone->nrPyramids[0]++;
625 }
626 }
627
628 template <typename Integer>
add_hyperplane(const size_t & new_generator,const FACETDATA<Integer> & positive,const FACETDATA<Integer> & negative,list<FACETDATA<Integer>> & NewHyps,bool known_to_be_simplicial)629 void Full_Cone<Integer>::add_hyperplane(const size_t& new_generator,
630 const FACETDATA<Integer>& positive,
631 const FACETDATA<Integer>& negative,
632 list<FACETDATA<Integer>>& NewHyps,
633 bool known_to_be_simplicial) {
634 // adds a new hyperplane found in find_new_facets to this cone (restricted to generators processed)
635
636 if (don_t_add_hyperplanes)
637 return;
638
639 size_t k;
640
641 FACETDATA<Integer> NewFacet;
642 NewFacet.Hyp.resize(dim);
643 NewFacet.GenInHyp.resize(nr_gen);
644 // NewFacet.is_positive_on_all_original_gens = false;
645 // NewFacet.is_negative_on_some_original_gen = false;
646
647 Integer help;
648
649 for (k = 0; k < dim; k++) {
650 NewFacet.Hyp[k] = negative.Hyp[k];
651 NewFacet.Hyp[k] *= positive.ValNewGen;
652 help = negative.ValNewGen;
653 if (help != 0) {
654 help *= positive.Hyp[k];
655 NewFacet.Hyp[k] -= help;
656 }
657 // NewFacet.Hyp[k] = positive.ValNewGen * negative.Hyp[k] - negative.ValNewGen * positive.Hyp[k];
658 if (!check_range(NewFacet.Hyp[k]))
659 break;
660 }
661
662 if (k == dim)
663 v_make_prime(NewFacet.Hyp);
664 else {
665 #pragma omp atomic
666 GMP_hyp++;
667 vector<mpz_class> mpz_neg(dim), mpz_pos(dim), mpz_sum(dim);
668 convert(mpz_neg, negative.Hyp);
669 convert(mpz_pos, positive.Hyp);
670 for (k = 0; k < dim; k++)
671 mpz_sum[k] =
672 convertTo<mpz_class>(positive.ValNewGen) * mpz_neg[k] - convertTo<mpz_class>(negative.ValNewGen) * mpz_pos[k];
673 v_make_prime(mpz_sum);
674 convert(NewFacet.Hyp, mpz_sum);
675 }
676
677 NewFacet.ValNewGen = 0;
678 NewFacet.GenInHyp = positive.GenInHyp & negative.GenInHyp; // new hyperplane contains old gen iff both pos and neg do
679 if (known_to_be_simplicial) {
680 NewFacet.simplicial = true;
681 }
682 else
683 set_simplicial(NewFacet);
684 NewFacet.GenInHyp.set(new_generator); // new hyperplane contains new generator
685 number_hyperplane(NewFacet, nrGensInCone, positive.Ident);
686
687 // check_facet(NewFacet, new_generator);
688 if(!pyramids_for_last_built_directly)
689 NewHyps.emplace_back(std::move(NewFacet));
690 else
691 make_pyramid_for_last_generator(NewFacet);
692 }
693
694 //---------------------------------------------------------------------------
695
696 template <typename Integer>
find_new_facets(const size_t & new_generator)697 void Full_Cone<Integer>::find_new_facets(const size_t& new_generator) {
698 // our Fourier-Motzkin implementation
699 // the special treatment of simplicial facets was inserted because of line shellings.
700 // At present these are not computed.
701
702 // to see if possible to replace the function .end with constant iterator since push-back is performed.
703
704 // for dimension 0 and 1 F-M is never necessary and can lead to problems
705 // when using dim-2
706 if (dim <= 1)
707 return;
708
709 // NEW: new_generator is the index of the generator being inserted
710
711 size_t i;
712 size_t subfacet_dim = dim - 2; // NEW dimension of subfacet
713 size_t facet_dim = dim - 1; // NEW dimension of facet
714
715 const bool tv_verbose = // true;
716 false; // verbose && !is_pyramid; // && Support_Hyperplanes.nr_of_rows()>10000; //verbose in this method call
717
718 // preparing the computations, the various types of facets are sorted into the deques
719 deque<FACETDATA<Integer>*> Pos_Simp, Pos_Non_Simp;
720 deque<FACETDATA<Integer>*> Neg_Simp, Neg_Non_Simp;
721 deque<FACETDATA<Integer>*> Neutral_Simp, Neutral_Non_Simp;
722
723 dynamic_bitset GenInPosHyp(nr_gen), GenInNegHyp(nr_gen); // here we collect the generators that lie in a
724 // positive resp. negative hyperplane
725
726 bool simplex;
727
728 if (tv_verbose)
729 verboseOutput() << "find_new_facets:" << flush;
730
731 for (auto& facet : Facets) {
732 if (facet.positive) {
733 GenInPosHyp |= facet.GenInHyp;
734 }
735 if (facet.negative) {
736 GenInNegHyp |= facet.GenInHyp;
737 }
738 }
739
740 dynamic_bitset Gen_BothSides(nr_gen); // indicator for generators that are in a negative as well as a positive supphyp
741 Gen_BothSides = GenInPosHyp & GenInNegHyp;
742 vector<key_t> Gen_BothSides_key;
743 for (i = 0; i < nr_gen; ++i) {
744 if (Gen_BothSides[i])
745 Gen_BothSides_key.push_back(i);
746 }
747
748 for (auto& facet : Facets) {
749 simplex = facet.simplicial; // at present simplicial, will become nonsimplicial if neutral
750
751 if (facet.neutral) {
752 facet.GenInHyp.set(new_generator); // Must be set explicitly !!
753 facet.simplicial = false; // simpliciality definitly gone with the new generator
754 if (simplex) {
755 Neutral_Simp.push_back(&facet); // simplicial without the new generator
756 }
757 else {
758 Neutral_Non_Simp.push_back(&facet); // nonsimplicial already without the new generator
759 }
760 continue;
761 }
762
763 size_t nr_relevant_gens = 0;
764
765 for (size_t i = 0; i < Gen_BothSides_key.size(); ++i) {
766 if (facet.GenInHyp[Gen_BothSides_key[i]])
767 nr_relevant_gens++;
768 }
769
770 if (nr_relevant_gens < subfacet_dim)
771 continue;
772
773 if (facet.positive) {
774 if (simplex) {
775 Pos_Simp.push_back(&facet);
776 }
777 else {
778 Pos_Non_Simp.push_back(&facet);
779 }
780 }
781 else if (facet.negative) {
782 if (simplex) {
783 Neg_Simp.push_back(&facet);
784 }
785 else {
786 Neg_Non_Simp.push_back(&facet);
787 }
788 }
789 }
790
791 // TO DO: Negativliste mit GenInPosHyp verfeinern, also die aussondern, die nicht genug positive Erz enthalten
792 // Eventuell sogar Rang-Test einbauen.
793 // Letzteres k�nnte man auch bei den positiven machen, bevor sie verarbeitet werden
794
795 size_t nr_PosSimp = Pos_Simp.size();
796 size_t nr_PosNonSimp = Pos_Non_Simp.size();
797 size_t nr_NegSimp = Neg_Simp.size();
798 size_t nr_NegNonSimp = Neg_Non_Simp.size();
799 size_t nr_NeuSimp = Neutral_Simp.size();
800 size_t nr_NeuNonSimp = Neutral_Non_Simp.size();
801
802 if (tv_verbose)
803 verboseOutput() << " PS " << nr_PosSimp << ", P " << nr_PosNonSimp << ", NS " << nr_NegSimp << ", N " << nr_NegNonSimp
804 << ", ZS " << nr_NeuSimp << ", Z " << nr_NeuNonSimp << endl;
805
806 if (tv_verbose)
807 verboseOutput() << "find_new_facets: subfacet of NS: " << flush;
808
809 vector<list<pair<dynamic_bitset, int>>> Neg_Subfacet_Multi(omp_get_max_threads());
810
811 // This parallel region cannot throw a NormalizException
812 // Next we produce the subfacets of the negative simplicial facets by threads
813
814 #pragma omp parallel
815 {
816 dynamic_bitset RelGen_NegHyp, subfacet;
817 size_t nr_RelGen_NegHyp;
818
819 #pragma omp for schedule(dynamic)
820 for (i = 0; i < nr_NegSimp; i++) {
821 RelGen_NegHyp = Gen_BothSides & Neg_Simp[i]->GenInHyp;
822
823 nr_RelGen_NegHyp = 0;
824 for (size_t j = 0; j < nr_gen; j++) {
825 if (RelGen_NegHyp.test(j))
826 nr_RelGen_NegHyp++;
827 if (nr_RelGen_NegHyp > subfacet_dim) {
828 break;
829 }
830 }
831
832 if (nr_RelGen_NegHyp == subfacet_dim) // only one subfacet to build
833 Neg_Subfacet_Multi[omp_get_thread_num()].push_back(pair<dynamic_bitset, int>(RelGen_NegHyp, i));
834
835 if (nr_RelGen_NegHyp == facet_dim) {
836 for (size_t k = 0; k < nr_gen; k++) {
837 if (RelGen_NegHyp.test(k)) {
838 subfacet = RelGen_NegHyp;
839 subfacet.reset(k); // remove k-th element from facet to obtain subfacet
840 Neg_Subfacet_Multi[omp_get_thread_num()].push_back(pair<dynamic_bitset, int>(subfacet, i));
841 }
842 }
843 }
844 }
845 }// parallel
846
847 // Now all threads get united
848 list<pair<dynamic_bitset, int>> Neg_Subfacet_Multi_United;
849 for (int i = 0; i < omp_get_max_threads(); ++i)
850 Neg_Subfacet_Multi_United.splice(Neg_Subfacet_Multi_United.begin(), Neg_Subfacet_Multi[i]);
851 Neg_Subfacet_Multi_United.sort();
852
853 if (tv_verbose)
854 verboseOutput() << Neg_Subfacet_Multi_United.size() << ", " << flush;
855
856 // remove negative subfacets shared by two neg simpl facets
857 for (auto jj = Neg_Subfacet_Multi_United.begin(); jj != Neg_Subfacet_Multi_United.end();) {
858 auto del = jj++;
859 if (jj != Neg_Subfacet_Multi_United.end() &&
860 (*jj).first == (*del).first) { // delete since is the intersection of two negative simplicies
861 Neg_Subfacet_Multi_United.erase(del);
862 del = jj++;
863 Neg_Subfacet_Multi_United.erase(del);
864 }
865 }
866
867 size_t nr_NegSubfMult = Neg_Subfacet_Multi_United.size();
868 if (tv_verbose)
869 verboseOutput() << " after removal " << nr_NegSubfMult << ", " << flush;
870
871 vector<list<FACETDATA<Integer>>> NewHypsSimp(nr_PosSimp);
872 vector<list<FACETDATA<Integer>>> NewHypsNonSimp(nr_PosNonSimp);
873
874 map<dynamic_bitset, int> Neg_Subfacet;
875 size_t nr_NegSubf = 0;
876
877 // size_t NrMatches=0, NrCSF=0, NrRank=0, NrComp=0, NrNewF=0;
878
879 /* deque<bool> Indi(nr_NegNonSimp);
880 for(size_t j=0;j<nr_NegNonSimp;++j)
881 Indi[j]=false; */
882
883 if (multithreaded_pyramid) {
884 nrTotalComparisons += nr_NegNonSimp * nr_PosNonSimp;
885 }
886 else {
887 nrTotalComparisons += nr_NegNonSimp * nr_PosNonSimp;
888 }
889
890 bool skip_remaining = false;
891 std::exception_ptr tmp_exception;
892
893 if ((using_GMP<Integer>() || using_renf<Integer>()) && Generators_float.nr_of_rows() == 0) {
894 bool potential_ranktest = false;
895 if (using_GMP<Integer>())
896 potential_ranktest =
897 (old_nr_supp_hyps > GMP_time_factor * dim * dim * dim / 3); // in this case the rank computation takes longer
898 if (using_renf<Integer>())
899 potential_ranktest = (old_nr_supp_hyps > renf_time_factor * dim * dim * dim / 3);
900 if (potential_ranktest)
901 convert(Generators_float, Generators);
902 }
903
904 //=====================================================================
905 // biohg parallel block from here
906
907 #pragma omp parallel
908 {
909 size_t i, j, k, nr_RelGen_PosHyp;
910 dynamic_bitset subfacet(dim - 2);
911 auto jj = Neg_Subfacet_Multi_United.begin();
912 size_t jjpos = 0;
913 int tn = omp_get_ancestor_thread_num(omp_start_level + 1);
914
915 // We remove negative simplicial subfacets that appear in neuitral facets or negative nonsimplicial facets
916 if (nr_PosNonSimp >= nr_NegNonSimp / 10) { // to prevent a desaster if there are very few positive facets,
917 bool found; // but many negative ones and pyramid decomposition is not applied
918
919 // This for region cannot throw a NormalizException
920 #pragma omp for schedule(dynamic)
921 for (size_t j = 0; j < nr_NegSubfMult; ++j) { // remove negative subfacets shared
922 for (; j > jjpos; ++jjpos, ++jj)
923 ; // by non-simpl neg or neutral facets
924 for (; j < jjpos; --jjpos, --jj)
925 ;
926
927 subfacet = (*jj).first;
928 found = false;
929 for (i = 0; i < nr_NeuSimp; i++) {
930 found = subfacet.is_subset_of(Neutral_Simp[i]->GenInHyp);
931 if (found)
932 break;
933 }
934 if (!found) {
935 for (i = 0; i < nr_NeuNonSimp; i++) {
936 found = subfacet.is_subset_of(Neutral_Non_Simp[i]->GenInHyp);
937 if (found)
938 break;
939 }
940 if (!found) {
941 for (i = 0; i < nr_NegNonSimp; i++) {
942 found = subfacet.is_subset_of(Neg_Non_Simp[i]->GenInHyp);
943 if (found)
944 break;
945 }
946 }
947 }
948 if (found) {
949 jj->second = -1;
950 }
951 }
952 }
953
954 #pragma omp single
955 { // remove elements that were found in the previous loop
956 auto last_inserted = Neg_Subfacet.begin(); // used to speedup insertion into the new map
957 for (auto jj = Neg_Subfacet_Multi_United.begin(); jj != Neg_Subfacet_Multi_United.end(); ++jj) {
958 if ((*jj).second != -1) {
959 last_inserted = Neg_Subfacet.insert(last_inserted, *jj);
960 }
961 }
962 nr_NegSubf = Neg_Subfacet.size();
963 }
964
965 #pragma omp single nowait
966 { Neg_Subfacet_Multi_United.clear(); }
967
968 //**********************************************************
969 // Now the matching of positive and negative facets starts *
970 // the outer loops run over the positive facets *
971 //**********************************************************
972
973 dynamic_bitset RelGen_PosHyp(nr_gen);
974
975 #pragma omp single nowait
976 if (tv_verbose) {
977 verboseOutput() << "PS vs NS and PS vs N , " << flush;
978 }
979
980 vector<key_t> key(nr_gen);
981 size_t nr_missing;
982 bool common_subfacet;
983
984 // we cannot use nowait here because of the way we handle exceptions in this loop
985 #pragma omp for schedule(dynamic) // nowait
986 for (size_t i = 0; i < nr_PosSimp; i++) {
987 if (skip_remaining)
988 continue;
989 try {
990 INTERRUPT_COMPUTATION_BY_EXCEPTION
991
992 RelGen_PosHyp = Gen_BothSides & Pos_Simp[i]->GenInHyp;
993 nr_RelGen_PosHyp = 0;
994 for (j = 0; j < nr_gen && nr_RelGen_PosHyp <= facet_dim; j++)
995 if (RelGen_PosHyp.test(j)) {
996 key[nr_RelGen_PosHyp] = j;
997 nr_RelGen_PosHyp++;
998 }
999
1000 if (nr_RelGen_PosHyp < subfacet_dim)
1001 continue;
1002
1003 // first PS vs NS
1004
1005 if (nr_RelGen_PosHyp == subfacet_dim) { // NEW slight change in logic. Positive simpl facet shared at most
1006 auto jj_map = Neg_Subfacet.find(RelGen_PosHyp); // one subfacet with negative simpl facet
1007 if (jj_map != Neg_Subfacet.end()) {
1008 add_hyperplane(new_generator, *Pos_Simp[i], *Neg_Simp[(*jj_map).second], NewHypsSimp[i], true);
1009 (*jj_map).second = -1; // block subfacet in further searches
1010 }
1011 }
1012 if (nr_RelGen_PosHyp == facet_dim) { // now there could be more such subfacets. We make all and search them.
1013 for (k = 0; k < nr_gen; k++) {
1014 INTERRUPT_COMPUTATION_BY_EXCEPTION
1015
1016 if (RelGen_PosHyp.test(k)) {
1017 subfacet = RelGen_PosHyp;
1018 subfacet.reset(k); // remove k-th element from facet to obtain subfacet
1019 auto jj_map = Neg_Subfacet.find(subfacet);
1020 if (jj_map != Neg_Subfacet.end()) {
1021 add_hyperplane(new_generator, *Pos_Simp[i], *Neg_Simp[(*jj_map).second], NewHypsSimp[i], true);
1022 (*jj_map).second = -1;
1023 // Indi[j]=true;
1024 }
1025 }
1026 }
1027 }
1028
1029 // now PS vs N
1030
1031 for (j = 0; j < nr_NegNonSimp; j++) { // search negative facet with common subfacet
1032
1033 INTERRUPT_COMPUTATION_BY_EXCEPTION
1034
1035 nr_missing = 0;
1036 common_subfacet = true;
1037 for (k = 0; k < nr_RelGen_PosHyp; k++) {
1038 if (!Neg_Non_Simp[j]->GenInHyp.test(key[k])) {
1039 nr_missing++;
1040 if (nr_missing == 2 || nr_RelGen_PosHyp == subfacet_dim) {
1041 common_subfacet = false;
1042 break;
1043 }
1044 }
1045 }
1046
1047 if (common_subfacet) {
1048 add_hyperplane(new_generator, *Pos_Simp[i], *Neg_Non_Simp[j], NewHypsSimp[i], true);
1049 if (nr_RelGen_PosHyp == subfacet_dim) // only one subfacet can lie in negative hyperplane
1050 break;
1051 }
1052 }
1053 } catch (const std::exception&) {
1054 tmp_exception = std::current_exception();
1055 skip_remaining = true;
1056 #pragma omp flush(skip_remaining)
1057 }
1058
1059 } // Done: PS vs NS and PS vs N
1060
1061 if (!skip_remaining) {
1062 #pragma omp single nowait
1063 if (tv_verbose) {
1064 verboseOutput() << "P vs NS and P vs N" << endl;
1065 }
1066
1067 // the lists below are made because we want to move successful reducers
1068 // to the top indeoendently in each thread
1069
1070 list<dynamic_bitset> Facets_0_1_thread;
1071 for (i = 0; i < nr_PosNonSimp; ++i)
1072 Facets_0_1_thread.push_back(Pos_Non_Simp[i]->GenInHyp);
1073 for (i = 0; i < nr_NegNonSimp; ++i)
1074 Facets_0_1_thread.push_back(Neg_Non_Simp[i]->GenInHyp);
1075 for (i = 0; i < nr_NeuNonSimp; ++i)
1076 Facets_0_1_thread.push_back(Neutral_Non_Simp[i]->GenInHyp);
1077 size_t nr_NonSimp = nr_PosNonSimp + nr_NegNonSimp + nr_NeuNonSimp;
1078
1079 bool ranktest;
1080 FACETDATA<Integer>*PosHyp_Pointer, *NegHyp_Pointer; // pointers to current hyperplanes
1081
1082 size_t missing_bound, nr_CommonGens;
1083 dynamic_bitset CommonGens(nr_gen);
1084 vector<key_t> common_key;
1085 common_key.reserve(nr_gen);
1086 vector<int> key_start(nrGensInCone);
1087
1088 #pragma omp for schedule(dynamic)
1089 for (size_t i = 0; i < nr_PosNonSimp; i++) { // Positive Non Simp vs.Negative Simp and Non Simp
1090
1091 if (skip_remaining)
1092 continue;
1093
1094 try {
1095 INTERRUPT_COMPUTATION_BY_EXCEPTION
1096
1097 auto jj_map = Neg_Subfacet.begin(); // First the Simp
1098 for (j = 0; j < nr_NegSubf; ++j, ++jj_map) {
1099 if ((*jj_map).second != -1) { // skip used subfacets
1100 if (jj_map->first.is_subset_of(Pos_Non_Simp[i]->GenInHyp)) {
1101 add_hyperplane(new_generator, *Pos_Non_Simp[i], *Neg_Simp[(*jj_map).second], NewHypsNonSimp[i],
1102 true);
1103 (*jj_map).second = -1; // has now been used
1104 }
1105 }
1106 }
1107
1108 // Now the NonSimp --- the critical task
1109
1110 PosHyp_Pointer = Pos_Non_Simp[i];
1111 RelGen_PosHyp =
1112 Gen_BothSides & PosHyp_Pointer->GenInHyp; // these are the potential vertices in an intersection
1113 nr_RelGen_PosHyp = 0;
1114 int last_existing = -1;
1115 for (size_t jj = 0; jj < nrGensInCone; jj++) // we make a "key" of the potential vertices in the intersection
1116 {
1117 j = GensInCone[jj];
1118 if (RelGen_PosHyp.test(j)) {
1119 key[nr_RelGen_PosHyp] = j;
1120 for (size_t kk = last_existing + 1; kk <= jj; kk++) // used in the extension test
1121 key_start[kk] = nr_RelGen_PosHyp; // to find out from which generator on both have existed
1122 nr_RelGen_PosHyp++;
1123 last_existing = jj;
1124 }
1125 }
1126 if (last_existing < (int)nrGensInCone - 1)
1127 for (size_t kk = last_existing + 1; kk < nrGensInCone; kk++)
1128 key_start[kk] = nr_RelGen_PosHyp;
1129
1130 if (nr_RelGen_PosHyp < subfacet_dim)
1131 continue;
1132
1133 // now nr_RelGen_PosHyp is the number of vertices in PosHyp_Pointer that have a chance to lie in a negative
1134 // facet and key contains the indices
1135
1136 missing_bound = nr_RelGen_PosHyp - subfacet_dim; // at most this number of generators can be missing
1137 // to have a chance for common subfacet
1138
1139 for (j = 0; j < nr_NegNonSimp; j++) {
1140 NegHyp_Pointer = Neg_Non_Simp[j];
1141
1142 if (PosHyp_Pointer->Ident == NegHyp_Pointer->Mother ||
1143 NegHyp_Pointer->Ident == PosHyp_Pointer->Mother) { // mother and daughter coming together
1144 add_hyperplane(new_generator, *PosHyp_Pointer, *NegHyp_Pointer, NewHypsNonSimp[i],
1145 false); // their intersection is a subfacet
1146 continue; // simplicial set in add_hyperplane
1147 }
1148
1149 bool extension_test = PosHyp_Pointer->BornAt == NegHyp_Pointer->BornAt ||
1150 (PosHyp_Pointer->BornAt < NegHyp_Pointer->BornAt && NegHyp_Pointer->Mother != 0) ||
1151 (NegHyp_Pointer->BornAt < PosHyp_Pointer->BornAt && PosHyp_Pointer->Mother != 0);
1152
1153 // extension_test=false;
1154
1155 size_t both_existing_from = key_start[max(PosHyp_Pointer->BornAt, NegHyp_Pointer->BornAt)];
1156
1157 nr_missing = 0;
1158 nr_CommonGens = 0;
1159 common_key.clear();
1160 size_t second_loop_bound = nr_RelGen_PosHyp;
1161 common_subfacet = true;
1162
1163 // We use the following criterion:
1164 // if the two facets are not mother and daughter (taken care of already), then
1165 // they cannot have intersected in a subfacet at the time when the second was born.
1166 // In other words: they can only intersect in a subfacet now, if at least one common vertex
1167 // has been added after the birth of the younger one.
1168 // this is indicated by "extended".
1169
1170 if (extension_test) {
1171 bool extended = false;
1172 second_loop_bound = both_existing_from; // fisrt we find the common vertices inserted from the step
1173 // where both facets existed the first time
1174 for (k = both_existing_from; k < nr_RelGen_PosHyp; k++) {
1175 if (!NegHyp_Pointer->GenInHyp.test(key[k])) {
1176 nr_missing++;
1177 if (nr_missing > missing_bound) {
1178 common_subfacet = false;
1179 break;
1180 }
1181 }
1182 else {
1183 extended = true; // in this case they have a common vertex added after their common existence
1184 common_key.push_back(key[k]);
1185 nr_CommonGens++;
1186 }
1187 }
1188
1189 if (!extended || !common_subfacet) //
1190 continue;
1191 }
1192
1193 for (k = 0; k < second_loop_bound; k++) { // now the remaining
1194 if (!NegHyp_Pointer->GenInHyp.test(key[k])) {
1195 nr_missing++;
1196 if (nr_missing > missing_bound) {
1197 common_subfacet = false;
1198 break;
1199 }
1200 }
1201 else {
1202 common_key.push_back(key[k]);
1203 nr_CommonGens++;
1204 }
1205 }
1206
1207 if (!common_subfacet)
1208 continue;
1209
1210 if (subfacet_dim <= 2) { // intersection of i and j is a subfacet
1211 add_hyperplane(new_generator, *PosHyp_Pointer, *NegHyp_Pointer, NewHypsNonSimp[i],
1212 false); // simplicial set in add_hyperplane
1213 /* #pragma omp atomic
1214 NrNewF++; */
1215 // Indi[j]=true;
1216 // cout << "Subfacet" << endl;
1217 continue;
1218 }
1219
1220 /* #pragma omp atomic
1221 NrCSF++;*/
1222
1223 // clock_t cl=clock();
1224
1225 // a priori values
1226 if (using_GMP<Integer>())
1227 ranktest = (nr_NonSimp > GMP_time_factor *dim*dim *nr_CommonGens/3); // in this case the rank computation takes longer
1228 else {
1229 if (using_renf<Integer>())
1230 ranktest = (nr_NonSimp > renf_time_factor * dim * dim * nr_CommonGens / 3);
1231 else
1232 ranktest = (nr_NonSimp > dim * dim * nr_CommonGens / 3);
1233 }
1234
1235 #ifdef NMZ_EXTENDED_TESTS
1236 if(test_linear_algebra_GMP)
1237 ranktest=true;
1238 #endif
1239
1240 if (Generators_float.nr_of_rows() > 0) {
1241 Matrix<nmz_float>& Test_float = Top_Cone->RankTest_float[tn];
1242 if (Test_float.rank_submatrix(Generators_float, common_key) < subfacet_dim) {
1243 ranktest = false;
1244 }
1245 }
1246
1247 if (ranktest) { //
1248 // cout << "Rang" << endl;
1249 Matrix<Integer>& Test = Top_Cone->RankTest[tn];
1250 if (Test.rank_submatrix(Generators, common_key) < subfacet_dim) {
1251 common_subfacet = false;
1252 }
1253 } // ranktest
1254 else { // now the comparison test
1255
1256 // cout << "comp " << Facets_0_1_thread.size() << endl;
1257
1258 /* #pragma omp atomic
1259 NrComp++; */
1260 auto a = Facets_0_1_thread.begin();
1261
1262 CommonGens = RelGen_PosHyp & NegHyp_Pointer->GenInHyp;
1263 /*for (; a != Facets_0_1_thread.end(); ++a) {
1264 bool contains = true;
1265 for(size_t i=0; i< nr_CommonGens; ++i){
1266 if(!(*a)[common_key[i]]){
1267 contains = false;
1268 break;
1269 }
1270 }
1271 if ((contains && *a != PosHyp_Pointer->GenInHyp) && (*a != NegHyp_Pointer->GenInHyp)) {
1272 common_subfacet = false;
1273 Facets_0_1_thread.splice(Facets_0_1_thread.begin(), Facets_0_1_thread,
1274 a); // for the "darwinistic" mewthod
1275 break;
1276 }
1277 }*/
1278
1279
1280 for (; a != Facets_0_1_thread.end(); ++a) {
1281 if (CommonGens.is_subset_of(*a) && (*a != PosHyp_Pointer->GenInHyp) &&
1282 (*a != NegHyp_Pointer->GenInHyp)) {
1283 common_subfacet = false;
1284 Facets_0_1_thread.splice(Facets_0_1_thread.begin(), Facets_0_1_thread,
1285 a); // for the "darwinistic" mewthod
1286 break;
1287 }
1288 }
1289 } // else
1290
1291 // cout << nr_CommonGens*ticks_rank_per_row << " " << nr_NonSimp*ticks_comp_per_supphyp << " " <<
1292 // clock()-cl << endl;
1293
1294 if (common_subfacet) { // intersection of i and j is a subfacet
1295 add_hyperplane(new_generator, *PosHyp_Pointer, *NegHyp_Pointer, NewHypsNonSimp[i],
1296 false); // simplicial set in add_hyperplane
1297 /* #pragma omp atomic
1298 NrNewF++; */
1299 // Indi[j]=true;
1300 // cout << "Subfacet" << endl;
1301 }
1302 }
1303 } catch (const std::exception&) {
1304 tmp_exception = std::current_exception();
1305 skip_remaining = true;
1306 #pragma omp flush(skip_remaining)
1307 }
1308 } // end for
1309 } // end !skip_remaining
1310 } // END parallel
1311
1312 if (!(tmp_exception == 0))
1313 std::rethrow_exception(tmp_exception);
1314 //=====================================================================
1315 // parallel until here
1316
1317 /* if(!is_pyramid)
1318 cout << "Matches " << NrMatches << " pot. common subf " << NrCSF << " rank test " << NrRank << " comp test "
1319 << NrComp << " neww hyps " << NrNewF << endl; */
1320
1321 for (i = 0; i < nr_PosSimp; i++)
1322 Facets.splice(Facets.end(), NewHypsSimp[i]);
1323
1324 for (i = 0; i < nr_PosNonSimp; i++)
1325 Facets.splice(Facets.end(), NewHypsNonSimp[i]);
1326
1327 // removing the negative hyperplanes
1328 // now done in build_cone
1329
1330 if (tv_verbose)
1331 verboseOutput() << "find_new_facets: done" << endl;
1332 }
1333
1334 //---------------------------------------------------------------------------
1335 // Pulloing triangulations are treated separately: they are not used for the computation of
1336 // other data. Determinants will be added in evaluate_triangulation.
1337 // Pyramid decomposition is not possible since the triangulation is not incremenral.
1338 // Therefore the fouble loop over support hyperplanes and simplices computed before
1339 // produces the new triangulation that replaces the triangulation computed before.
1340 //
1341 // The only alternative we see would be to form the pyramids of the new generator
1342 // and the invisible support hyperplanes. Done consequently this results in a
1343 // recursive algorithm over the face lattice.
1344 template <typename Integer>
update_pulling_triangulation(const size_t & new_generator)1345 void Full_Cone<Integer>::update_pulling_triangulation(const size_t& new_generator) {
1346
1347 size_t listsize = old_nr_supp_hyps; // Facets.size();
1348 vector<typename list<FACETDATA<Integer>>::iterator> invisible;
1349 invisible.reserve(listsize);
1350
1351 listsize = 0;
1352 for (auto i = Facets.begin(); i != Facets.end(); ++i) {
1353 if (i->positive) { // invisible facet
1354 invisible.push_back(i);
1355 listsize++;
1356 }
1357 }
1358
1359 list<SHORTSIMPLEX<Integer>> NewTriangulationBuffer;
1360
1361 std::exception_ptr tmp_exception;
1362 bool skip_remaining = false;
1363
1364 // Integer TotalDetSum = 0;
1365
1366 #pragma omp parallel
1367 {
1368 list<SHORTSIMPLEX<Integer>> Triangulation_kk;
1369 vector<key_t> key(dim);
1370 // Integer DetSum = 0;
1371
1372 // if we only want a partial triangulation but came here because of a deep level
1373 // mark if this part of the triangulation has not to be evaluated
1374
1375 #pragma omp for schedule(dynamic)
1376 for (size_t kk = 0; kk < listsize; ++kk) {
1377
1378 if(skip_remaining)
1379 continue;
1380
1381 try {
1382 INTERRUPT_COMPUTATION_BY_EXCEPTION
1383
1384 auto H = invisible[kk];
1385
1386 if (H->simplicial) { // simplicial
1387 size_t l = 0;
1388 for (size_t k = 0; k < nr_gen; k++) {
1389 if (H->GenInHyp[k] == 1) {
1390 key[l] = k;
1391 l++;
1392 }
1393 }
1394 key[dim - 1] = new_generator;
1395 // Integer test_vol = Generators.submatrix(key).vol();
1396 // DetSum += test_vol;
1397 store_key(key, 0, 0, Triangulation_kk);
1398 continue;
1399 } // end simplicial
1400
1401
1402 for(auto& S: TriangulationBuffer){
1403 bool one_vertex_not_in_hyp = false;
1404 bool no_facet_in_hyp = false;
1405 key_t not_in_hyp = 0; // to make the compiler happy
1406 key = S.key;
1407 for(size_t k=0; k< dim; ++k){
1408 if (!H->GenInHyp.test(key[k])){
1409 if(one_vertex_not_in_hyp){
1410 no_facet_in_hyp =true;
1411 break;
1412 }
1413 one_vertex_not_in_hyp = true;
1414 not_in_hyp = k;
1415 }
1416 }
1417 if(no_facet_in_hyp)
1418 continue;
1419 key[not_in_hyp] = new_generator;
1420 store_key(key, 0, 0, Triangulation_kk);
1421 // DetSum += Generators.submatrix(key).vol();
1422
1423 } // S
1424
1425
1426 } catch (const std::exception&) {
1427 tmp_exception = std::current_exception();
1428 skip_remaining = true;
1429 #pragma omp flush(skip_remaining)
1430 }
1431
1432 } // omp for kk
1433
1434 if (multithreaded_pyramid) {
1435 #pragma omp critical(TRIANG)
1436 {
1437 NewTriangulationBuffer.splice(NewTriangulationBuffer.end(), Triangulation_kk);
1438 // TotalDetSum += DetSum;
1439 }
1440 }
1441 else{
1442 NewTriangulationBuffer.splice(NewTriangulationBuffer.end(), Triangulation_kk);
1443 // TotalDetSum += DetSum;
1444 }
1445
1446 } // parallel
1447
1448 if (!(tmp_exception == 0))
1449 std::rethrow_exception(tmp_exception);
1450
1451 TriangulationBuffer.clear();
1452 TriangulationBuffer.splice(TriangulationBuffer.begin(),NewTriangulationBuffer);
1453 /* cout << "DDDDDD " << TotalDetSum << endl;
1454 vector<bool> GenInd = in_triang;
1455 GenInd[new_generator] = true;
1456 Cone<Integer> TestCone(Type::cone,Generators.submatrix(GenInd));
1457 TestCone.setVerbose(false);
1458 TestCone.compute(ConeProperty::Multiplicity,ConeProperty::Descent);
1459 cout << "CCCCCC " << TestCone.getMultiplicity() << endl; */
1460 }
1461
1462 //---------------------------------------------------------------------------
1463
1464 template <typename Integer>
extend_triangulation(const size_t & new_generator)1465 void Full_Cone<Integer>::extend_triangulation(const size_t& new_generator) {
1466 // extends the triangulation of this cone by including new_generator
1467 // simplicial facets save us from searching the "brother" in the existing triangulation
1468 // to which the new simplex gets attached
1469
1470 if(pulling_triangulation){
1471 update_pulling_triangulation(new_generator);
1472 return;
1473 }
1474
1475 size_t listsize = old_nr_supp_hyps; // Facets.size();
1476 vector<typename list<FACETDATA<Integer>>::iterator> visible;
1477 visible.reserve(listsize);
1478
1479 listsize = 0;
1480 for (auto i = Facets.begin(); i != Facets.end(); ++i) {
1481 if (i->negative) { // visible facet
1482 visible.push_back(i);
1483 listsize++;
1484 }
1485 }
1486
1487 std::exception_ptr tmp_exception;
1488
1489 auto oldTriBack = --TriangulationBuffer.end();
1490 #pragma omp parallel
1491 {
1492 size_t k, l;
1493 bool one_not_in_i, not_in_facet;
1494 size_t not_in_i = 0;
1495 // size_t facet_dim=dim-1;
1496 // size_t nr_in_i=0;
1497
1498 list<SHORTSIMPLEX<Integer>> Triangulation_kk;
1499
1500 vector<key_t> key(dim);
1501
1502 // if we only want a partial triangulation but came here because of a deep level
1503 // mark if this part of the triangulation has not to be evaluated
1504 bool skip_eval = false;
1505 bool skip_remaining = false;
1506
1507 #pragma omp for schedule(dynamic)
1508 for (size_t kk = 0; kk < listsize; ++kk) {
1509
1510 if(skip_remaining)
1511 continue;
1512
1513 try {
1514 INTERRUPT_COMPUTATION_BY_EXCEPTION
1515
1516 auto i = visible[kk];
1517
1518 skip_eval = Top_Cone->do_partial_triangulation && i->ValNewGen == -1 && is_hyperplane_included(*i);
1519
1520 if (i->simplicial) { // simplicial
1521 l = 0;
1522 for (k = 0; k < nr_gen; k++) {
1523 if (i->GenInHyp[k] == 1) {
1524 key[l] = k;
1525 l++;
1526 }
1527 }
1528 key[dim - 1] = new_generator;
1529
1530 if (skip_eval)
1531 store_key(key, 0, 0, Triangulation_kk);
1532 else
1533 store_key(key, -i->ValNewGen, 0, Triangulation_kk);
1534 continue;
1535 } // end simplicial
1536
1537 size_t irrelevant_vertices = 0;
1538 for (size_t vertex = 0; vertex < nrGensInCone; ++vertex) {
1539 if (i->GenInHyp[GensInCone[vertex]] == 0) // lead vertex not in hyperplane
1540 continue;
1541
1542 if (irrelevant_vertices < dim - 2) {
1543 ++irrelevant_vertices;
1544 continue;
1545 }
1546
1547 auto j = TriSectionFirst[vertex];
1548 bool done = false;
1549 for (; !done; j++) {
1550 done = (j == TriSectionLast[vertex]);
1551 key = j->key;
1552 one_not_in_i = false; // true indicates that one gen of simplex is not in hyperplane
1553 not_in_facet = false; // true indicates that a second gen of simplex is not in hyperplane
1554 for (k = 0; k < dim; k++) {
1555 if (!i->GenInHyp.test(key[k])) {
1556 if (one_not_in_i) {
1557 not_in_facet = true;
1558 break;
1559 }
1560 one_not_in_i = true;
1561 not_in_i = k;
1562 }
1563 }
1564
1565 if (not_in_facet) // simplex does not share facet with hyperplane
1566 continue;
1567
1568 key[not_in_i] = new_generator;
1569 if (skip_eval)
1570 store_key(key, 0, j->vol, Triangulation_kk);
1571 else
1572 store_key(key, -i->ValNewGen, j->vol, Triangulation_kk);
1573
1574 } // j
1575
1576 } // for vertex
1577
1578 } catch (const std::exception&) {
1579 tmp_exception = std::current_exception();
1580 skip_remaining = true;
1581 #pragma omp flush(skip_remaining)
1582 }
1583
1584 } // omp for kk
1585
1586 if (multithreaded_pyramid) {
1587 #pragma omp critical(TRIANG)
1588 TriangulationBuffer.splice(TriangulationBuffer.end(), Triangulation_kk);
1589 }
1590 else
1591 TriangulationBuffer.splice(TriangulationBuffer.end(), Triangulation_kk);
1592
1593 } // parallel
1594
1595 if (!(tmp_exception == 0))
1596 std::rethrow_exception(tmp_exception);
1597
1598 // GensInCone.push_back(new_generator); // now in extend_cone
1599 TriSectionFirst.push_back(++oldTriBack);
1600 TriSectionLast.push_back(--TriangulationBuffer.end());
1601 }
1602
1603 //---------------------------------------------------------------------------
1604
1605 template <typename Integer>
store_key(const vector<key_t> & key,const Integer & height,const Integer & mother_vol,list<SHORTSIMPLEX<Integer>> & Triangulation)1606 void Full_Cone<Integer>::store_key(const vector<key_t>& key,
1607 const Integer& height,
1608 const Integer& mother_vol,
1609 list<SHORTSIMPLEX<Integer>>& Triangulation) {
1610 // stores a simplex given by key and height in Triangulation
1611 // mother_vol is the volume of the simplex to which the new one is attached
1612
1613 SHORTSIMPLEX<Integer> newsimplex;
1614 newsimplex.key = key;
1615 newsimplex.height = height;
1616 newsimplex.vol = 0;
1617
1618 if (multithreaded_pyramid) {
1619 #pragma omp atomic
1620 TriangulationBufferSize++;
1621 }
1622 else {
1623 TriangulationBufferSize++;
1624 }
1625 int tn;
1626 if (omp_get_level() == omp_start_level)
1627 tn = 0;
1628 else
1629 tn = omp_get_ancestor_thread_num(omp_start_level + 1);
1630
1631 if (do_only_multiplicity) {
1632 // directly compute the volume
1633 if (mother_vol == 1)
1634 newsimplex.vol = height;
1635 // the multiplicity is computed in SimplexEvaluator
1636 for (size_t i = 0; i < dim; i++) // and needs the key in TopCone numbers
1637 newsimplex.key[i] = Top_Key[newsimplex.key[i]];
1638
1639 if (keep_triangulation)
1640 sort(newsimplex.key.begin(), newsimplex.key.end());
1641 Top_Cone->SimplexEval[tn].evaluate(newsimplex);
1642 // restore the local generator numbering, needed in extend_triangulation
1643 newsimplex.key = key;
1644 }
1645 if (height == 0)
1646 Top_Cone->triangulation_is_partial = true;
1647
1648 if (keep_triangulation) {
1649 Triangulation.push_back(newsimplex);
1650 return;
1651 }
1652
1653 bool Simpl_available = true;
1654
1655 if (Top_Cone->FS[tn].empty()) {
1656 if (Top_Cone->FreeSimpl.empty()) {
1657 Simpl_available = false;
1658 }
1659 else {
1660 #pragma omp critical(FREESIMPL)
1661 {
1662 if (Top_Cone->FreeSimpl.empty()) {
1663 Simpl_available = false;
1664 }
1665 else {
1666 // take 1000 simplices from FreeSimpl or what you can get
1667 auto F = Top_Cone->FreeSimpl.begin();
1668 size_t q;
1669 for (q = 0; q < 1000; ++q, ++F) {
1670 if (F == Top_Cone->FreeSimpl.end())
1671 break;
1672 }
1673
1674 if (q < 1000)
1675 Top_Cone->FS[tn].splice(Top_Cone->FS[tn].begin(), Top_Cone->FreeSimpl);
1676 else
1677 Top_Cone->FS[tn].splice(Top_Cone->FS[tn].begin(), Top_Cone->FreeSimpl, Top_Cone->FreeSimpl.begin(), F);
1678 } // if empty global (critical)
1679 } // critical
1680 } // if empty global
1681 } // if empty thread
1682
1683 if (Simpl_available) {
1684 Triangulation.splice(Triangulation.end(), Top_Cone->FS[tn], Top_Cone->FS[tn].begin());
1685 Triangulation.back() = newsimplex;
1686 }
1687 else {
1688 Triangulation.push_back(newsimplex);
1689 }
1690 }
1691
1692 #ifdef ENFNORMALIZ
1693 template <>
store_key(const vector<key_t> & key,const renf_elem_class & height,const renf_elem_class & mother_vol,list<SHORTSIMPLEX<renf_elem_class>> & Triangulation)1694 void Full_Cone<renf_elem_class>::store_key(const vector<key_t>& key,
1695 const renf_elem_class& height,
1696 const renf_elem_class& mother_vol,
1697 list<SHORTSIMPLEX<renf_elem_class>>& Triangulation) {
1698 // stores a simplex given by key and height in Triangulation
1699 // mother_vol is the volume of the simplex to which the new one is attached
1700
1701 SHORTSIMPLEX<renf_elem_class> newsimplex;
1702 newsimplex.key = key;
1703 newsimplex.height = height;
1704 newsimplex.vol = 0;
1705
1706 if (multithreaded_pyramid) {
1707 #pragma omp atomic
1708 TriangulationBufferSize++;
1709 }
1710 else {
1711 TriangulationBufferSize++;
1712 }
1713 int tn;
1714 if (omp_get_level() == 0)
1715 tn = 0;
1716 else
1717 tn = omp_get_ancestor_thread_num(1);
1718
1719 if (height == 0)
1720 Top_Cone->triangulation_is_partial = true;
1721
1722 if (keep_triangulation) {
1723 Triangulation.push_back(newsimplex);
1724 return;
1725 }
1726
1727 bool Simpl_available = true;
1728
1729 if (Top_Cone->FS[tn].empty()) {
1730 if (Top_Cone->FreeSimpl.empty()) {
1731 Simpl_available = false;
1732 }
1733 else {
1734 #pragma omp critical(FREESIMPL)
1735 {
1736 if (Top_Cone->FreeSimpl.empty()) {
1737 Simpl_available = false;
1738 }
1739 else {
1740 // take 1000 simplices from FreeSimpl or what you can get
1741 auto F = Top_Cone->FreeSimpl.begin();
1742 size_t q;
1743 for (q = 0; q < 1000; ++q, ++F) {
1744 if (F == Top_Cone->FreeSimpl.end())
1745 break;
1746 }
1747
1748 if (q < 1000)
1749 Top_Cone->FS[tn].splice(Top_Cone->FS[tn].begin(), Top_Cone->FreeSimpl);
1750 else
1751 Top_Cone->FS[tn].splice(Top_Cone->FS[tn].begin(), Top_Cone->FreeSimpl, Top_Cone->FreeSimpl.begin(), F);
1752 } // if empty global (critical)
1753 } // critical
1754 } // if empty global
1755 } // if empty thread
1756
1757 if (Simpl_available) {
1758 Triangulation.splice(Triangulation.end(), Top_Cone->FS[tn], Top_Cone->FS[tn].begin());
1759 Triangulation.back() = newsimplex;
1760 }
1761 else {
1762 Triangulation.push_back(newsimplex);
1763 }
1764 }
1765 #endif
1766
1767 //---------------------------------------------------------------------------
1768
1769 // We measure times for small and large pyramids in order to better control
1770 // which pyramids should be declared large.
1771 //
1772 // THIS IS A CRITICAL SUBROUTINE because of evaluate_large_rec_pyramids.
1773 // One must take care that it does not change the state of *this.
1774 // don_t_add_hyperplanes should keep it under control.
1775 // One must not only avoid adding hyperplanes, but also changing the
1776 // numbering scheme for hyperplanes.
1777 //
1778 template <typename Integer>
small_vs_large(const size_t new_generator)1779 void Full_Cone<Integer>::small_vs_large(const size_t new_generator) {
1780 IsLarge = vector<bool>(nr_gen, false);
1781
1782 don_t_add_hyperplanes = true; // during time measurement the addition of hyperplanes is blocked
1783
1784 int save_nr_threads = omp_get_max_threads(); // must block parallelization
1785 omp_set_num_threads(1); // in small pyramids
1786
1787 nr_pyrs_timed = vector<size_t>(nr_gen);
1788 time_of_large_pyr = vector<chrono::nanoseconds>(nr_gen);
1789 time_of_small_pyr = vector<chrono::nanoseconds>(nr_gen);
1790
1791 auto hyp = Facets.begin();
1792 vector<key_t> Pyramid_key;
1793 size_t start_level = omp_get_level();
1794
1795 size_t check_period = 25;
1796
1797 for (size_t kk = 0; kk < old_nr_supp_hyps; ++kk, ++hyp) {
1798 if (kk % check_period != 0)
1799 continue;
1800
1801 if (hyp->ValNewGen >= 0) // facet not visible
1802 continue;
1803
1804 Pyramid_key.clear(); // make data of new pyramid
1805 Pyramid_key.push_back(new_generator);
1806 for (size_t i = 0; i < nr_gen; i++) {
1807 if (in_triang[i] && hyp->GenInHyp.test(i)) {
1808 Pyramid_key.push_back(i);
1809 }
1810 }
1811
1812 bool large = (largePyramidFactor * Comparisons[Pyramid_key.size() - dim] > old_nr_supp_hyps); // a priori decision
1813 if (large)
1814 continue;
1815
1816 if (nr_pyrs_timed[Pyramid_key.size()] >= 5)
1817 continue;
1818
1819 // we first treat it as small pyramid
1820 auto cl0 = chrono::high_resolution_clock::now();
1821 process_pyramid(Pyramid_key, new_generator, store_level, 0, true, hyp,
1822 start_level); // is recursive, 0 blocks triangulation
1823 auto cl1 = chrono::high_resolution_clock::now();
1824 time_of_small_pyr[Pyramid_key.size()] += cl1 - cl0;
1825 nr_pyrs_timed[Pyramid_key.size()]++;
1826 // now as large pyramid
1827 LargeRecPyrs.push_back(*hyp);
1828 }
1829
1830 take_time_of_large_pyr = true;
1831 bool save_verbose = verbose;
1832 verbose = false;
1833 evaluate_large_rec_pyramids(new_generator);
1834 verbose = save_verbose;
1835 take_time_of_large_pyr = false;
1836
1837 int kk;
1838 for (kk = nr_gen - 1; kk >= (int)dim; --kk) {
1839 if (time_of_small_pyr[kk].count() == 0)
1840 continue;
1841 if (time_of_small_pyr[kk] > time_of_large_pyr[kk])
1842 IsLarge[kk] = true;
1843 else
1844 break;
1845 }
1846
1847 // cout << "First large " << kk+1 << endl;
1848
1849 don_t_add_hyperplanes = false;
1850 omp_set_num_threads(save_nr_threads);
1851
1852 assert(Facets.size() == old_nr_supp_hyps);
1853 }
1854
1855 //---------------------------------------------------------------------------
1856
1857 template <typename Integer>
process_pyramids(const size_t new_generator,const bool recursive)1858 void Full_Cone<Integer>::process_pyramids(const size_t new_generator, const bool recursive) {
1859 /*
1860
1861 We distinguish two types of pyramids:
1862
1863 (i) recursive pyramids that give their support hyperplanes back to the mother.
1864 (ii) independent pyramids that are not linked to the mother.
1865
1866 The parameter "recursive" indicates whether the pyramids that will be created
1867 in process_pyramid(s) are of type (i) or (ii).
1868
1869 Every pyramid can create subpyramids of both types (not the case in version 2.8 - 2.10).
1870
1871 Whether "this" is of type (i) or (ii) is indicated by do_all_hyperplanes.
1872
1873 The creation of (sub)pyramids of type (i) can be blocked by setting recursion_allowed=false.
1874 (Not done in this version.)
1875
1876 is_pyramid==false for the top_cone and ==true else.
1877
1878 multithreaded_pyramid indicates whether parallelization takes place within the
1879 computation of a pyramid or whether it is computed in a single thread (defined in build_cone).
1880
1881 Recursie pyramids are processed immediately after creation (as in 2.8). However, there
1882 are two exceptions:
1883
1884 (a) In order to avoid very long waiting times for the computation of the "large" ones,
1885 these are treated as follows: the support hyperplanes of "this" coming from their bases
1886 (as negative hyperplanes of "this") are computed by matching them with the
1887 positive hyperplanes of "this". This Fourier-Motzkin step is much more
1888 efficient if a pyramid is large. For triangulation a large recursive
1889 pyramid is then stored as a pyramid of type (ii).
1890
1891 (b) If "this" is processed in a parallelized loop calling process_pyramids, then
1892 the loop in process_pyramids cannot be interrupted for the evaluation of simplices. As a
1893 consequence an extremely long lst of simplices could arise if many small subpyramids of "this"
1894 are created in process_pyramids. In order to prevent this dangeous effect, small recursive
1895 subpyramids are stored for later triangulation if the simplex buffer has reached its
1896 size bound.
1897
1898 Pyramids of type (ii) are stpred in Pyramids. The store_level of the created pyramids is 0
1899 for all pyramids created (possibly recursively) from the top cone. Pyramids created
1900 in evaluate_stored_pyramids get the store level for their subpyramids in that routine and
1901 transfer it to their recursive daughters. (correction March 4, 2015).
1902
1903 Note: the top cone has pyr_level=-1. The pyr_level has no algorithmic relevance
1904 at present, but it shows the depth of the pyramid recursion at which the pyramid has been
1905 created.
1906
1907 */
1908
1909 if ((using_renf<Integer>() || using_GMP<Integer>()) && Generators_float.nr_of_rows() == 0) {
1910 // Generators.pretty_print(cout);
1911 convert(Generators_float, Generators);
1912 }
1913
1914 if (!is_pyramid && !time_measured && recursive) { // (using_GMP<Integer>() || using_renf<Integer>()) &&
1915 rank_time();
1916 cmp_time();
1917 /* ticks_quot=(ticks_rank_per_row/ticks_comp_per_supphyp)/ticks_norm_quot;
1918 if(verbose)
1919 verboseOutput() << "Normed quotient " << ticks_quot << endl;*/
1920 time_measured = true;
1921 }
1922
1923 IsLarge.clear();
1924
1925 if (using_renf<Integer>() && recursive && !is_pyramid && (!do_partial_triangulation || do_triangulation)) {
1926 /*if(verbose)
1927 verboseOutput() << "ticks_rank_per_row "
1928 << ticks_rank_per_row.count() << " (nanoseconds)" << endl;*/
1929 if (ticks_rank_per_row.count() > 2000)
1930 small_vs_large(new_generator);
1931 }
1932
1933 size_t start_level = omp_get_level(); // allows us to check that we are on level 0
1934 // outside the loop and can therefore call evaluation
1935 // in order to empty the buffers
1936
1937 if (!is_pyramid && verbose){
1938 verboseOutput() << "Building pyramids";
1939 if(recursive){
1940 verboseOutput() << " for support hyperplanes";
1941 if(do_triangulation || do_partial_triangulation)
1942 verboseOutput() << " and triangulation";
1943 }
1944 else
1945 verboseOutput() << " for triangulation";
1946 verboseOutput() << endl;
1947 }
1948
1949 vector<key_t> Pyramid_key;
1950 Pyramid_key.reserve(nr_gen);
1951 bool skip_triang; // make hyperplanes but skip triangulation (recursive pyramids only)
1952
1953 // deque<bool> done(old_nr_supp_hyps, false);
1954 bool skip_remaining;
1955 std::exception_ptr tmp_exception;
1956 size_t start_kk = 0;
1957
1958 size_t ii = 0;
1959 deque<typename list<FACETDATA<Integer> >::iterator > FacetIts(old_nr_supp_hyps);
1960 for(auto F = Facets.begin(); F!= Facets.end(); ++F, ++ii){
1961 FacetIts[ii] = F;
1962 }
1963
1964 const long VERBOSE_STEPS = 50;
1965 long step_x_size = old_nr_supp_hyps - VERBOSE_STEPS;
1966 const size_t RepBound = 10000;
1967 string collected_points;
1968
1969 do { // repeats processing until all hyperplanes have been processed
1970
1971 auto hyp = Facets.begin();
1972 skip_remaining = false;
1973 bool fresh_loop_start = true;
1974
1975 #pragma omp parallel for private(skip_triang, hyp) firstprivate(Pyramid_key, collected_points) schedule(dynamic)
1976 for (size_t kk = start_kk; kk < old_nr_supp_hyps; ++kk) {
1977 if (skip_remaining)
1978 continue;
1979
1980 if (verbose && old_nr_supp_hyps >= RepBound) {
1981 #pragma omp critical(VERBOSE)
1982 {
1983 if(fresh_loop_start)
1984 cout << collected_points;
1985 fresh_loop_start = false;
1986 while ((long)(kk * VERBOSE_STEPS) >= step_x_size) {
1987 step_x_size += old_nr_supp_hyps;
1988 verboseOutput() << "." << flush;
1989 collected_points +=".";
1990 }
1991 }
1992 }
1993
1994 try {
1995
1996 INTERRUPT_COMPUTATION_BY_EXCEPTION
1997
1998 //if (done[kk])
1999 // continue;
2000
2001 if(FacetIts[kk] == Facets.end())
2002 continue;
2003
2004 hyp = FacetIts[kk];
2005
2006 // done[kk] = true;
2007 FacetIts[kk] = Facets.end();
2008
2009 if (hyp->ValNewGen == 0) { // MUST BE SET HERE
2010 hyp->GenInHyp.set(new_generator);
2011 if (recursive)
2012 hyp->simplicial = false; // in the recursive case
2013 }
2014
2015 if (hyp->ValNewGen >= 0){ // facet not visible
2016 if(pyramids_for_last_built_directly)
2017 make_pyramid_for_last_generator(*hyp);
2018 continue;
2019 }
2020
2021 skip_triang = false;
2022 if (Top_Cone->do_partial_triangulation && hyp->ValNewGen >= -1) { // ht1 criterion
2023 skip_triang = is_hyperplane_included(*hyp);
2024 if (skip_triang) {
2025 Top_Cone->triangulation_is_partial = true;
2026 if (!recursive) {
2027 continue;
2028 }
2029 }
2030 }
2031
2032 Pyramid_key.clear(); // make data of new pyramid
2033 Pyramid_key.push_back(new_generator);
2034 for (size_t i = 0; i < nr_gen; i++) {
2035 if (in_triang[i] && hyp->GenInHyp.test(i)) {
2036 Pyramid_key.push_back(i);
2037 }
2038 }
2039
2040 // now we can store the new pyramid at the right place (or finish the simplicial ones)
2041 if (recursive && skip_triang) { // mark as "do not triangulate"
2042 process_pyramid(Pyramid_key, new_generator, store_level, 0, recursive, hyp, start_level);
2043 }
2044 else { // default
2045 process_pyramid(Pyramid_key, new_generator, store_level, -hyp->ValNewGen, recursive, hyp, start_level);
2046 }
2047 // interrupt parallel execution if it is really parallel
2048 // to keep the triangulationand pyramid buffers under control
2049 if (start_level == 0) {
2050 if (check_evaluation_buffer_size() || Top_Cone->check_pyr_buffer(store_level) || Top_Cone->check_pyr_buffer(0)) {
2051 if(verbose && !skip_remaining)
2052 verboseOutput() << endl;
2053 skip_remaining = true;
2054 }
2055 }
2056
2057 } catch (const std::exception&) {
2058 tmp_exception = std::current_exception();
2059 skip_remaining = true;
2060 #pragma omp flush(skip_remaining)
2061 }
2062 } // end parallel loop over hyperplanes
2063
2064 if (!(tmp_exception == 0))
2065 std::rethrow_exception(tmp_exception);
2066
2067 if (!omp_in_parallel())
2068 try_offload(0);
2069
2070 if (start_level == 0 && check_evaluation_buffer_size()) {
2071 Top_Cone->evaluate_triangulation();
2072 }
2073
2074 if (start_level == 0 && Top_Cone->check_pyr_buffer(store_level)) {
2075 Top_Cone->evaluate_stored_pyramids(store_level);
2076 }
2077
2078 if (start_level == 0 && Top_Cone->check_pyr_buffer(0)) {
2079 Top_Cone->evaluate_stored_pyramids(0);
2080 }
2081
2082 if (verbose && old_nr_supp_hyps >= RepBound)
2083 verboseOutput() << endl;
2084
2085 // for(;start_kk < old_nr_supp_hyps && done[start_kk]; ++start_kk);
2086
2087 for(;start_kk < old_nr_supp_hyps && FacetIts[start_kk] == Facets.end(); ++start_kk);
2088
2089 } while (start_kk < old_nr_supp_hyps);
2090
2091 // cout << float_comp << " " << wrong << " " << wrong_short << endl;
2092
2093 // wrong_positive=0;
2094 // wrong_negative=0;
2095 // total_comp_large_pyr=0;
2096
2097 evaluate_large_rec_pyramids(new_generator);
2098
2099 // cout << total_comp_large_pyr << " " << wrong_positive << " " << wrong_negative << endl;
2100 }
2101
2102 //---------------------------------------------------------------------------
2103
2104 template <typename Integer>
process_pyramid(const vector<key_t> & Pyramid_key,const size_t new_generator,const size_t store_level,Integer height,const bool recursive,typename list<FACETDATA<Integer>>::iterator hyp,size_t start_level)2105 void Full_Cone<Integer>::process_pyramid(const vector<key_t>& Pyramid_key,
2106 const size_t new_generator,
2107 const size_t store_level,
2108 Integer height,
2109 const bool recursive,
2110 typename list<FACETDATA<Integer>>::iterator hyp,
2111 size_t start_level) {
2112 // processes simplicial pyramids directly, stores other pyramids into their depots
2113
2114 #pragma omp atomic
2115 Top_Cone->totalNrPyr++;
2116
2117 #ifdef NMZ_EXTENDED_TESTS
2118 if( (!test_small_pyramids || (test_small_pyramids && !test_large_pyramids) ) && (Pyramid_key.size() == dim))
2119
2120 #else
2121 if (Pyramid_key.size() == dim) // simplicial pyramid completely done here for saving memory
2122 #endif
2123 {
2124 #pragma omp atomic
2125 Top_Cone->nrSimplicialPyr++;
2126 if (recursive) { // the facets may be facets of the mother cone and if recursive==true must be given back
2127 Matrix<Integer> H(dim, dim);
2128 Integer dummy_vol;
2129 int tn;
2130 if (omp_get_level() == omp_start_level)
2131 tn = 0;
2132 else
2133 tn = omp_get_ancestor_thread_num(omp_start_level + 1);
2134 Generators.simplex_data(Pyramid_key, H, dummy_vol, Top_Cone->WorkMat[tn], Top_Cone->UnitMat, false);
2135 list<FACETDATA<Integer>> NewFacets;
2136 FACETDATA<Integer> NewFacet;
2137 NewFacet.GenInHyp.resize(nr_gen);
2138 for (size_t i = 0; i < dim; i++) {
2139 swap(NewFacet.Hyp,H[i]);
2140 NewFacet.GenInHyp.set();
2141 NewFacet.GenInHyp.reset(i);
2142 NewFacet.simplicial = true;
2143 // NewFacet.is_positive_on_all_original_gens = false;
2144 // NewFacet.is_negative_on_some_original_gen = false;
2145 NewFacets.push_back(NewFacet);
2146 }
2147 vector<bool> Pyr_in_triang(dim, true);
2148 select_supphyps_from(NewFacets, new_generator, Pyramid_key,
2149 Pyr_in_triang); // takes itself care of multithreaded_pyramid
2150 }
2151 if (height != 0 && (do_triangulation || do_partial_triangulation)) {
2152 if (multithreaded_pyramid) {
2153 std::exception_ptr tmp_exception;
2154 #pragma omp critical(TRIANG)
2155 {
2156 try {
2157 store_key(Pyramid_key, height, 0, TriangulationBuffer);
2158 nrTotalComparisons += dim * dim / 2;
2159 } catch (const std::exception&) {
2160 tmp_exception = std::current_exception();
2161 }
2162 } // end critical
2163 if (!(tmp_exception == 0))
2164 std::rethrow_exception(tmp_exception);
2165 }
2166 else {
2167 store_key(Pyramid_key, height, 0, TriangulationBuffer);
2168 nrTotalComparisons += dim * dim / 2;
2169 }
2170 }
2171 }
2172 else { // non-simplicial
2173
2174 bool large;
2175
2176 if (IsLarge.size() == 0) { // no measurement in Small_vs_large
2177 long large_factor = largePyramidFactor;
2178 if (time_measured) {
2179 mpq_class large_factor_mpq((double) ticks_rank_per_row.count()/1000); // 1000 because of nanosecinds
2180 mpz_class add = round(large_factor_mpq);
2181 large_factor += convertToLong(add);
2182 }
2183 large = (large_factor * Comparisons[Pyramid_key.size() - dim] > old_nr_supp_hyps);
2184 }
2185 else { // with measurement
2186 large = (largePyramidFactor * Comparisons[Pyramid_key.size() - dim] > old_nr_supp_hyps);
2187 large = large || IsLarge[Pyramid_key.size()];
2188 }
2189
2190 #ifdef NMZ_EXTENDED_TESTS
2191 if(test_large_pyramids)
2192 large=true;
2193 #endif
2194
2195 if (!recursive || (large && (do_triangulation || do_partial_triangulation) &&
2196 height != 0)) { // must also store for triangulation if recursive and large
2197 vector<key_t> key_wrt_top(Pyramid_key.size());
2198 for (size_t i = 0; i < Pyramid_key.size(); i++)
2199 key_wrt_top[i] = Top_Key[Pyramid_key[i]];
2200 #pragma omp critical(STOREPYRAMIDS)
2201 {
2202 // cout << "store_level " << store_level << " large " << large << " pyr level " << pyr_level << endl;
2203 Top_Cone->Pyramids[store_level].push_back(key_wrt_top);
2204 Top_Cone->nrPyramids[store_level]++;
2205 } // critical
2206 if (!recursive) // in this case we need only store for future triangulation, and that has been done
2207 return;
2208 }
2209 // now we are in the recursive case and must compute support hyperplanes of the subpyramid
2210 if (large) { // large recursive pyramid
2211 if (multithreaded_pyramid) {
2212 #pragma omp critical(LARGERECPYRS)
2213 LargeRecPyrs.push_back(*hyp); // LargeRecPyrs are kept and evaluated locally
2214 }
2215 else
2216 LargeRecPyrs.push_back(*hyp);
2217 return; // done with the large recusive pyramids
2218 }
2219
2220 // only recursive small ones left
2221
2222 // pyrtime=clock();
2223
2224 Full_Cone<Integer> Pyramid(*this, Pyramid_key);
2225 Pyramid.Mother = this;
2226 Pyramid.Mother_Key = Pyramid_key; // need these data to give back supphyps
2227 Pyramid.apex = new_generator;
2228 if (height == 0) { // indicates "do not triangulate"
2229 Pyramid.do_triangulation = false;
2230 Pyramid.do_partial_triangulation = false;
2231 Pyramid.do_Hilbert_basis = false;
2232 Pyramid.do_deg1_elements = false;
2233 }
2234
2235 bool store_for_triangulation =
2236 (store_level != 0) // loop in process_pyramids cannot be interrupted
2237 && (Pyramid.do_triangulation || Pyramid.do_partial_triangulation) // we must (partially) triangulate
2238 && (start_level != 0 &&
2239 Top_Cone->TriangulationBufferSize > 2 * EvalBoundTriang); // evaluation buffer already full // EvalBoundTriang
2240
2241 if (store_for_triangulation) {
2242 vector<key_t> key_wrt_top(Pyramid_key.size());
2243 for (size_t i = 0; i < Pyramid_key.size(); i++)
2244 key_wrt_top[i] = Top_Key[Pyramid_key[i]];
2245 #pragma omp critical(STOREPYRAMIDS)
2246 {
2247 Top_Cone->Pyramids[store_level].push_back(key_wrt_top);
2248 Top_Cone->nrPyramids[store_level]++;
2249 } // critical
2250 // Now we must suppress immediate triangulation
2251 Pyramid.do_triangulation = false;
2252 Pyramid.do_partial_triangulation = false;
2253 Pyramid.do_Hilbert_basis = false;
2254 Pyramid.do_deg1_elements = false;
2255 }
2256
2257 Pyramid.build_cone();
2258
2259 // cout << "Pyramid ticks " << clock() - pyrtime << endl;
2260
2261 if (multithreaded_pyramid) {
2262 #pragma omp atomic
2263 nrTotalComparisons += Pyramid.nrTotalComparisons;
2264 }
2265 else
2266 nrTotalComparisons += Pyramid.nrTotalComparisons;
2267 } // else non-simplicial
2268 }
2269
2270 //---------------------------------------------------------------------------
2271
2272 template <typename Integer>
find_and_evaluate_start_simplex()2273 void Full_Cone<Integer>::find_and_evaluate_start_simplex() {
2274 // it is absolutely necessary to chooses the start simplex as the lex smallest+
2275 // in order to be consistent with pyramid decomposition
2276
2277 size_t i, j;
2278
2279 vector<key_t> key = find_start_simplex();
2280 assert(key.size() == dim); // safety heck
2281 if (verbose) {
2282 verboseOutput() << "Start simplex ";
2283 for (unsigned int i : key)
2284 verboseOutput() << i + 1 << " ";
2285 verboseOutput() << endl;
2286 }
2287 Matrix<Integer> H(dim, dim);
2288 Integer vol;
2289
2290 int tn;
2291 if (omp_get_level() == omp_start_level)
2292 tn = 0;
2293 else
2294 tn = omp_get_ancestor_thread_num(omp_start_level + 1);
2295 Generators.simplex_data(key, H, vol, Top_Cone->WorkMat[tn], Top_Cone->UnitMat, do_partial_triangulation || do_triangulation);
2296
2297 assert(key.size() == dim); // safety heck
2298
2299 // cout << "Nach First " << clock()-pyrtime << endl;
2300
2301 // cout << "Nach LinAl " << clock()-pyrtime << endl;
2302
2303 // H.pretty_print(cout);
2304
2305 for (i = 0; i < dim; i++) {
2306 in_triang[key[i]] = true;
2307 GensInCone.push_back(key[i]);
2308 if (deg1_triangulation && isComputed(ConeProperty::Grading))
2309 deg1_triangulation = (gen_degrees[key[i]] == 1);
2310 }
2311
2312 nrGensInCone = dim;
2313
2314 nrTotalComparisons = dim * dim / 2;
2315 // if(!time_measured){
2316 if (using_GMP<Integer>())
2317 nrTotalComparisons *= (GMP_time_factor / 4); // because of the linear algebra involved in this routine
2318 if (using_renf<Integer>())
2319 nrTotalComparisons *= (renf_time_factor / 4);
2320 /*}
2321 else{
2322 if(using_GMP<Integer>())
2323 nrTotalComparisons*=(GMP_time_factor/4)*ticks_quot;
2324 if(using_renf<Integer>())
2325 nrTotalComparisons*=(renf_time_factor/4)*ticks_quot;
2326 }*/
2327
2328 Comparisons.push_back(nrTotalComparisons);
2329
2330 for (i = 0; i < dim; i++) {
2331 FACETDATA<Integer> NewFacet;
2332 NewFacet.GenInHyp.resize(nr_gen);
2333 // NewFacet.is_positive_on_all_original_gens = false;
2334 // NewFacet.is_negative_on_some_original_gen = false;
2335 swap(NewFacet.Hyp,H[i]);
2336 NewFacet.simplicial = true; // indeed, the start simplex is simplicial
2337 for (j = 0; j < dim; j++)
2338 if (j != i)
2339 NewFacet.GenInHyp.set(key[j]);
2340 NewFacet.ValNewGen = -1; // must be taken negative since opposite facet
2341 number_hyperplane(NewFacet, 0, 0); // created with gen 0
2342 Facets.emplace_back(std::move(NewFacet)); // was visible before adding this vertex
2343 }
2344
2345 Integer factor;
2346 if (!is_pyramid) {
2347 // define Order_Vector, decides which facets of the simplices are excluded
2348 Order_Vector = vector<Integer>(dim, 0);
2349 // Matrix<Integer> G=S.read_generators();
2350 for (i = 0; i < dim; i++) {
2351 factor = (unsigned long)(1 + i % 10); // (2*(rand()%(2*dim))+3);
2352 for (j = 0; j < dim; j++)
2353 Order_Vector[j] += factor * Generators[key[i]][j];
2354 }
2355 }
2356
2357 // the volume is an upper bound for the height
2358 if (do_triangulation || (do_partial_triangulation && vol > 1)) {
2359 store_key(key, vol, 1, TriangulationBuffer);
2360 if (do_only_multiplicity && !using_renf<Integer>()) {
2361 #pragma omp atomic
2362 TotDet++;
2363 }
2364 }
2365 else if (do_partial_triangulation) {
2366 triangulation_is_partial = true;
2367 }
2368
2369 if (do_triangulation) { // we must prepare the sections of the triangulation
2370 for (i = 0; i < dim; i++) {
2371 // GensInCone.push_back(key[i]); // now done in first loop since always needed
2372 TriSectionFirst.push_back(TriangulationBuffer.begin());
2373 TriSectionLast.push_back(TriangulationBuffer.begin());
2374 }
2375 }
2376
2377 // cout << "Nach Start " << clock()-pyrtime << endl;
2378 }
2379
2380 //---------------------------------------------------------------------------
2381
2382 template <typename Integer>
select_supphyps_from(list<FACETDATA<Integer>> & NewFacets,const size_t new_generator,const vector<key_t> & Pyramid_key,const vector<bool> & Pyr_in_triang)2383 void Full_Cone<Integer>::select_supphyps_from(list<FACETDATA<Integer>>& NewFacets,
2384 const size_t new_generator,
2385 const vector<key_t>& Pyramid_key,
2386 const vector<bool>& Pyr_in_triang) {
2387 // the mother cone (=this) selects supphyps from the list NewFacets supplied by the daughter
2388 // the daughter provides the necessary information via the parameters
2389
2390 size_t i;
2391 dynamic_bitset in_Pyr(nr_gen);
2392 for (i = 0; i < Pyramid_key.size(); i++) {
2393 in_Pyr.set(Pyramid_key[i]);
2394 }
2395 // the new generator is always the first in the pyramid
2396 assert(Pyramid_key[0] == new_generator);
2397
2398 bool new_global_hyp;
2399 FACETDATA<Integer> NewFacet;
2400 // NewFacet.is_positive_on_all_original_gens = false;
2401 // NewFacet.is_negative_on_some_original_gen = false;
2402 NewFacet.GenInHyp.resize(nr_gen);
2403 Integer test;
2404 for (auto& pyr_hyp : NewFacets) {
2405 if (!pyr_hyp.GenInHyp.test(0)) // new gen not in hyp
2406 continue;
2407 new_global_hyp = true;
2408 for (i = 0; i < nr_gen; ++i) {
2409 if (in_Pyr.test(i) || !in_triang[i])
2410 continue;
2411 test = v_scalar_product(Generators[i], pyr_hyp.Hyp);
2412 if (test <= 0) {
2413 new_global_hyp = false;
2414 break;
2415 }
2416 }
2417 if (new_global_hyp) {
2418 swap(NewFacet.Hyp,pyr_hyp.Hyp);
2419 NewFacet.GenInHyp.reset();
2420 // size_t gens_in_facet=0;
2421 for (i = 0; i < Pyramid_key.size(); ++i) {
2422 if (in_triang[Pyramid_key[i]]) // this satisfied in the standard setting where the pyramid key is strictly
2423 // ascending after
2424 assert(Pyr_in_triang[i]); // the first entry and the start simplex of the pyramid is lex smallest
2425 if (pyr_hyp.GenInHyp.test(i) && in_triang[Pyramid_key[i]]) {
2426 NewFacet.GenInHyp.set(Pyramid_key[i]);
2427 // gens_in_facet++;
2428 }
2429 }
2430 /* for (i=0; i<nr_gen; ++i) {
2431 if (NewFacet.GenInHyp.test(i) && in_triang[i]) {
2432 gens_in_facet++;
2433 }
2434 }*/
2435 // gens_in_facet++; // Note: new generator not yet in in_triang
2436 NewFacet.GenInHyp.set(new_generator);
2437 NewFacet.simplicial = pyr_hyp.simplicial; // (gens_in_facet==dim-1);
2438 // check_simpliciality_hyperplane(NewFacet);
2439 number_hyperplane(NewFacet, nrGensInCone, 0); // mother unknown
2440
2441 if (don_t_add_hyperplanes)
2442 continue;
2443
2444 if(!pyramids_for_last_built_directly){
2445 if (multithreaded_pyramid) {
2446 #pragma omp critical(GIVEBACKHYPS)
2447 Facets.push_back(NewFacet);
2448 }
2449 else {
2450 Facets.push_back(NewFacet);
2451 }
2452 }
2453 else
2454 make_pyramid_for_last_generator(NewFacet);
2455 }
2456 }
2457 }
2458
2459 //---------------------------------------------------------------------------
2460 template <typename Integer>
match_neg_hyp_with_pos_hyps(const FACETDATA<Integer> & Neg,size_t new_generator,const vector<FACETDATA<Integer> * > & PosHyps,dynamic_bitset & GenIn_PosHyp,vector<list<dynamic_bitset>> & Facets_0_1)2461 void Full_Cone<Integer>::match_neg_hyp_with_pos_hyps(const FACETDATA<Integer>& Neg,
2462 size_t new_generator,
2463 const vector<FACETDATA<Integer>*>& PosHyps,
2464 dynamic_bitset& GenIn_PosHyp,
2465 vector<list<dynamic_bitset>>& Facets_0_1) {
2466 size_t missing_bound, nr_common_gens;
2467 vector<key_t> common_key;
2468 common_key.reserve(nr_gen);
2469 vector<key_t> key(nr_gen);
2470 bool common_subfacet;
2471 // list<FACETDATA<Integer>> NewHyp;
2472 size_t subfacet_dim = dim - 2;
2473 size_t nr_missing;
2474 list<FACETDATA<Integer>> NewHyps;
2475 Matrix<Integer> Test(0, dim);
2476
2477 int tn;
2478 if (omp_get_level() == omp_start_level)
2479 tn = 0;
2480 else
2481 tn = omp_get_ancestor_thread_num(omp_start_level + 1);
2482
2483 dynamic_bitset RelGens_InNegHyp = Neg.GenInHyp & GenIn_PosHyp; // we intersect with the set of gens in positive hyps
2484
2485 vector<int> key_start(nrGensInCone);
2486 size_t nr_RelGens_InNegHyp = 0;
2487 size_t j;
2488 int last_existing = -1;
2489 for (size_t jj = 0; jj < nrGensInCone; jj++) {
2490 j = GensInCone[jj];
2491 if (RelGens_InNegHyp.test(j)) {
2492 key[nr_RelGens_InNegHyp] = j;
2493 for (size_t kk = last_existing + 1; kk <= jj; kk++)
2494 key_start[kk] = nr_RelGens_InNegHyp;
2495 nr_RelGens_InNegHyp++;
2496 last_existing = jj;
2497 }
2498 }
2499 if (last_existing < (int)nrGensInCone - 1)
2500 for (size_t kk = last_existing + 1; kk < nrGensInCone; kk++)
2501 key_start[kk] = nr_RelGens_InNegHyp;
2502
2503 if (nr_RelGens_InNegHyp < dim - 2)
2504 return;
2505
2506 missing_bound = nr_RelGens_InNegHyp - subfacet_dim; // at most this number of generators can be missing
2507 // to have a chance for common subfacet
2508
2509 for (const auto& Pos : PosHyps) { // match Neg with the given Pos
2510
2511 INTERRUPT_COMPUTATION_BY_EXCEPTION
2512
2513 if (Neg.Ident == Pos->Mother || Pos->Ident == Neg.Mother) { // mother and daughter coming together
2514 // their intersection is a subfacet
2515 add_hyperplane(new_generator, *Pos, Neg, NewHyps, false); // simplicial set in add_hyperplane
2516 continue;
2517 }
2518
2519 bool extension_test = Neg.BornAt == Pos->BornAt || (Neg.BornAt < Pos->BornAt && Pos->Mother != 0) ||
2520 (Pos->BornAt < Neg.BornAt && Neg.Mother != 0);
2521
2522 size_t both_existing_from = key_start[max(Neg.BornAt, Pos->BornAt)];
2523
2524 nr_missing = 0;
2525 nr_common_gens = 0;
2526 common_key.clear();
2527 size_t second_loop_bound = nr_RelGens_InNegHyp;
2528 common_subfacet = true;
2529 dynamic_bitset common_gens(nr_gen);
2530
2531 if (extension_test) {
2532 bool extended = false;
2533 second_loop_bound = both_existing_from;
2534 for (size_t k = both_existing_from; k < nr_RelGens_InNegHyp; k++) {
2535 if (!Pos->GenInHyp.test(key[k])) {
2536 nr_missing++;
2537 if (nr_missing > missing_bound) {
2538 common_subfacet = false;
2539 break;
2540 }
2541 }
2542 else {
2543 extended = true;
2544 common_key.push_back(key[k]);
2545 common_gens.set(key[k]);
2546 nr_common_gens++;
2547 }
2548 }
2549
2550 if (!extended || !common_subfacet) //
2551 continue;
2552 }
2553
2554 for (size_t k = 0; k < second_loop_bound; k++) {
2555 if (!Pos->GenInHyp.test(key[k])) {
2556 nr_missing++;
2557 if (nr_missing > missing_bound) {
2558 common_subfacet = false;
2559 break;
2560 }
2561 }
2562 else {
2563 common_key.push_back(key[k]);
2564 common_gens.set(key[k]);
2565 nr_common_gens++;
2566 }
2567 }
2568
2569 if (!common_subfacet)
2570 continue;
2571
2572 assert(nr_common_gens >= subfacet_dim);
2573
2574 // bool negative_predicted=false, positive_predicted=false;
2575
2576 if (!Pos->simplicial) {
2577 // #pragma omp atomic
2578 // total_comp_large_pyr++;
2579
2580 bool ranktest;
2581
2582 if (time_measured) {
2583 ranktest = (ticks_rank_per_row.count() * nr_common_gens < (unsigned long) ticks_per_cand.count());
2584 // casting ticks_per_cand.count() as unsigned long should be harmless
2585 }
2586 else { // a priori values
2587 if (using_GMP<Integer>())
2588 ranktest = (old_nr_supp_hyps > GMP_time_factor * dim * dim * nr_common_gens /
2589 3); // in this case the rank computation takes longer
2590 else {
2591 if (using_renf<Integer>())
2592 ranktest = (old_nr_supp_hyps > renf_time_factor * dim * dim * nr_common_gens / 3);
2593 else
2594 ranktest = (old_nr_supp_hyps > dim * dim * nr_common_gens / 3);
2595 }
2596 }
2597 #ifdef NMZ_EXTENDED_TESTS
2598 int help=rand() % 2;
2599 if(help == 0)
2600 ranktest=true;
2601 else
2602 ranktest=false;
2603 #endif
2604
2605 // if(!ranktest)
2606 // cout << " No Rank " << endl;
2607
2608 // ranktest=true;
2609
2610 /* if(nr_common_gens==subfacet_dim)
2611 ranktest=false;*/
2612
2613 /* clock_t cl;
2614
2615 if(verbose && time_measured){
2616 verboseOutput() << ticks_rank_per_row*nr_common_gens << " " << ticks_per_cand << endl;
2617 cl=clock();
2618 }*/
2619
2620 // ranktest=true;
2621
2622 if (ranktest && Generators_float.nr_of_rows() > 0) {
2623 Matrix<nmz_float>& Test_float = Top_Cone->RankTest_float[tn];
2624 if (Test_float.rank_submatrix(Generators_float, common_key) < subfacet_dim) {
2625 ranktest = false;
2626 // negative_predicted=true;
2627 }
2628 else {
2629 // positive_predicted=true;
2630 }
2631 }
2632
2633 if (ranktest) {
2634 // cout << "Rank" << endl;
2635 Matrix<Integer>& Test = Top_Cone->RankTest[tn];
2636 if (Test.rank_submatrix(Generators, common_key) < subfacet_dim)
2637 common_subfacet = false; // don't make a hyperplane
2638 }
2639 else { // now the comparison test
2640 // cout << "Compare" << endl;
2641 for (auto hp_t = Facets_0_1[tn].begin(); hp_t != Facets_0_1[tn].end(); ++hp_t) {
2642 if (common_gens.is_subset_of(*hp_t) && (*hp_t != Neg.GenInHyp) && (*hp_t != Pos->GenInHyp)) {
2643 Facets_0_1[tn].splice(Facets_0_1[tn].begin(), Facets_0_1[tn], hp_t); // successful reducer to the front
2644 common_subfacet = false;
2645 break;
2646 }
2647 }
2648
2649 } // else
2650
2651 /* if(verbose && time_measured){
2652 cl=clock()-cl;
2653 verboseOutput() << cl << endl;
2654 }
2655
2656 if(common_subfacet && verbose)
2657 verboseOutput() << "Subfacet" << endl;*/
2658 } // !simplicial
2659
2660 /* if(negative_predicted && common_subfacet){
2661 #pragma omp atomic
2662 wrong_negative++;
2663 }
2664 if(positive_predicted && !common_subfacet){
2665 #pragma omp atomic
2666 wrong_positive++;
2667 }*/
2668
2669 if (common_subfacet) {
2670 add_hyperplane(new_generator, *Pos, Neg, NewHyps, false); // simplicial set in add_hyperplane
2671 }
2672 } // for
2673
2674 if (multithreaded_pyramid)
2675 #pragma omp critical(GIVEBACKHYPS)
2676 Facets.splice(Facets.end(), NewHyps);
2677 else
2678 Facets.splice(Facets.end(), NewHyps);
2679 }
2680
2681 //---------------------------------------------------------------------------
2682 template <typename Integer>
collect_pos_supphyps(vector<FACETDATA<Integer> * > & PosHyps,dynamic_bitset & GenIn_PosHyp,size_t & nr_pos)2683 void Full_Cone<Integer>::collect_pos_supphyps(vector<FACETDATA<Integer>*>& PosHyps, dynamic_bitset& GenIn_PosHyp, size_t& nr_pos) {
2684 // positive facets are collected in a list
2685
2686 auto ii = Facets.begin();
2687 nr_pos = 0;
2688
2689 for (size_t ij = 0; ij < old_nr_supp_hyps; ++ij, ++ii)
2690 if (ii->ValNewGen > 0) {
2691 GenIn_PosHyp |= ii->GenInHyp;
2692 PosHyps.push_back(&(*ii));
2693 nr_pos++;
2694 }
2695 }
2696
2697 //---------------------------------------------------------------------------
2698 template <typename Integer>
evaluate_large_rec_pyramids(size_t new_generator)2699 void Full_Cone<Integer>::evaluate_large_rec_pyramids(size_t new_generator) {
2700 size_t nrLargeRecPyrs = LargeRecPyrs.size();
2701 if (nrLargeRecPyrs == 0)
2702 return;
2703
2704 vector<list<dynamic_bitset>> Facets_0_1(omp_get_max_threads());
2705
2706 size_t nr_non_simplicial = 0;
2707
2708 auto Fac = Facets.begin();
2709 for (size_t i = 0; i < old_nr_supp_hyps; ++i, ++Fac) {
2710 if (Fac->simplicial)
2711 continue;
2712 Facets_0_1[0].push_back(Fac->GenInHyp);
2713 nr_non_simplicial++;
2714 }
2715 for (int j = 1; j < omp_get_max_threads(); ++j)
2716 Facets_0_1[j] = Facets_0_1[0];
2717
2718 if (verbose)
2719 verboseOutput() << "large pyramids " << nrLargeRecPyrs << endl;
2720
2721 vector<FACETDATA<Integer>*> PosHyps;
2722 dynamic_bitset GenIn_PosHyp(nr_gen);
2723 size_t nr_pos;
2724 collect_pos_supphyps(PosHyps, GenIn_PosHyp, nr_pos);
2725
2726 nrTotalComparisons += nr_pos * nrLargeRecPyrs;
2727 std::exception_ptr tmp_exception;
2728
2729 const long VERBOSE_STEPS = 50;
2730 long step_x_size = nrLargeRecPyrs - VERBOSE_STEPS;
2731 const size_t RepBound = 100;
2732
2733 // clock_t cl=clock();
2734 /* auto LP=LargeRecPyrs.begin();
2735 for(size_t i=0; i<nrLargeRecPyrs; i++,++LP){
2736 if(i%100 ==1)
2737 match_neg_hyp_with_pos_hyps(*LP,new_generator,PosHyps,GenIn_PosHyp,true,nr_cand,Facets_0_1);
2738 }
2739 cl=clock()-cl;
2740 ticks_per_cand=(double) cl/(double) nr_cand;
2741 if(verbose)
2742 verboseOutput() << "Ticks per cand " << ticks_per_cand << endl;*/
2743
2744 ticks_per_cand = ticks_comp_per_supphyp * nr_non_simplicial; // estimated time for testing an irreducible by comparison
2745
2746 bool skip_remaining = false;
2747
2748 #pragma omp parallel if (!take_time_of_large_pyr)
2749 {
2750 size_t ppos = 0;
2751 auto p = LargeRecPyrs.begin();
2752
2753 #pragma omp for schedule(dynamic)
2754 for (size_t i = 0; i < nrLargeRecPyrs; i++) {
2755 if (skip_remaining)
2756 continue;
2757
2758 for (; i > ppos; ++ppos, ++p)
2759 ;
2760 for (; i < ppos; --ppos, --p)
2761 ;
2762
2763 if (verbose && nrLargeRecPyrs >= RepBound) {
2764 #pragma omp critical(VERBOSE)
2765 while ((long)(i * VERBOSE_STEPS) >= step_x_size) {
2766 step_x_size += nrLargeRecPyrs;
2767 verboseOutput() << "." << flush;
2768 }
2769 }
2770
2771 // cout << "=================================" << endl;
2772
2773 // cout << "Neg Hyp " << i << endl;
2774
2775 // clock_t cl;
2776 // cl= clock();
2777
2778 try {
2779 INTERRUPT_COMPUTATION_BY_EXCEPTION
2780
2781 chrono::time_point<chrono::high_resolution_clock> cl_large_0(chrono::nanoseconds(0));
2782 if (take_time_of_large_pyr) {
2783 cl_large_0 = chrono::high_resolution_clock::now();
2784 }
2785
2786 match_neg_hyp_with_pos_hyps(*p, new_generator, PosHyps, GenIn_PosHyp, Facets_0_1);
2787
2788 if (take_time_of_large_pyr) {
2789 auto cl_large_1 = chrono::high_resolution_clock::now();
2790 size_t nr_pyr_gens = 0;
2791 for (size_t i = 0; i < nr_gen; ++i)
2792 if (p->GenInHyp[i])
2793 nr_pyr_gens++;
2794 nr_pyr_gens++; // for the apex of the pyramid
2795 time_of_large_pyr[nr_pyr_gens] += cl_large_1 - cl_large_0;
2796 }
2797 } catch (const std::exception&) {
2798 tmp_exception = std::current_exception();
2799 skip_remaining = true;
2800 #pragma omp flush(skip_remaining)
2801 }
2802
2803 // cl=clock()-cl;
2804 // cout << "Neg Hyp " << i << " ticks " << cl << endl;
2805 }
2806 } // parallel
2807 if (!(tmp_exception == 0))
2808 std::rethrow_exception(tmp_exception);
2809
2810 if (verbose && nrLargeRecPyrs >= RepBound)
2811 verboseOutput() << endl;
2812
2813 LargeRecPyrs.clear();
2814 }
2815
2816 //---------------------------------------------------------------------------
2817
2818 template <typename Integer>
check_pyr_buffer(const size_t level)2819 bool Full_Cone<Integer>::check_pyr_buffer(const size_t level) {
2820 if (level == 0)
2821 return (nrPyramids[0] > EvalBoundLevel0Pyr);
2822 else
2823 return (nrPyramids[level] > EvalBoundPyr);
2824 }
2825
2826 //---------------------------------------------------------------------------
2827
2828 #ifdef NMZ_MIC_OFFLOAD
2829 template <>
try_offload(size_t max_level)2830 void Full_Cone<long long>::try_offload(size_t max_level) {
2831 if (!is_pyramid && _Offload_get_device_number() < 0) // dynamic check for being on CPU (-1)
2832 {
2833 if (max_level >= nrPyramids.size())
2834 max_level = nrPyramids.size() - 1;
2835 for (size_t level = 0; level <= max_level; ++level) {
2836 if (nrPyramids[level] >= 100) {
2837 // cout << "XXX: Try offload of level " << level << " pyramids ..." << endl;
2838 mic_offloader.offload_pyramids(*this, level);
2839 break;
2840 }
2841 }
2842 }
2843 }
2844
2845 template <typename Integer>
try_offload(size_t max_level)2846 void Full_Cone<Integer>::try_offload(size_t max_level) {
2847 }
2848 // else it is implemented in the header
2849
2850 template <typename Integer>
try_offload_loc(long place,size_t max_level)2851 void Full_Cone<Integer>::try_offload_loc(long place, size_t max_level) {
2852 verboseOutput() << "From place " << place << " "
2853 << "level " << max_level << endl;
2854 try_offload(max_level);
2855 }
2856
2857 #endif // NMZ_MIC_OFFLOAD
2858
2859 //---------------------------------------------------------------------------
2860
2861 template <typename Integer>
evaluate_stored_pyramids(const size_t level)2862 void Full_Cone<Integer>::evaluate_stored_pyramids(const size_t level) {
2863 // evaluates the stored non-recursive pyramids
2864
2865 #ifdef NMZ_MIC_OFFLOAD
2866 Pyramids_scrambled[level] = false;
2867
2868 if (level == 0 && _Offload_get_device_number() >= 0) {
2869 verboseOutput() << "Start evaluation of " << nrPyramids[level] << " pyrs on level " << level << endl;
2870 // verboseOutput() << "In parallel " << omp_in_parallel() << endl;
2871 }
2872 #endif // NMZ_MIC_OFFLOAD
2873
2874 if (Pyramids[level].empty())
2875 return;
2876
2877 assert(omp_get_level() == omp_start_level); // assert(!omp_in_parallel());
2878 assert(!is_pyramid);
2879
2880 if (Pyramids.size() < level + 2) {
2881 Pyramids.resize(level + 2); // provide space for a new generation
2882 nrPyramids.resize(level + 2, 0);
2883 Pyramids_scrambled.resize(level + 2, false);
2884 }
2885
2886 size_t eval_down_to = 0;
2887
2888 #ifdef NMZ_MIC_OFFLOAD
2889 #ifndef __MIC__
2890 // only on host and if offload is available
2891 if (level == 0 && nrPyramids[0] > EvalBoundLevel0Pyr) {
2892 eval_down_to = EvalBoundLevel0Pyr;
2893 }
2894 #endif
2895 #endif
2896
2897 vector<char> Done(nrPyramids[level], 0);
2898 if (verbose) {
2899 verboseOutput() << "**************************************************" << endl;
2900
2901 for (size_t l = 0; l <= level; ++l) {
2902 if (nrPyramids[l] > 0) {
2903 verboseOutput() << "level " << l << " pyramids remaining: " << nrPyramids[l] << endl;
2904 }
2905 }
2906 verboseOutput() << "**************************************************" << endl;
2907 }
2908 size_t ppos;
2909 bool skip_remaining;
2910 std::exception_ptr tmp_exception;
2911
2912 while (nrPyramids[level] > eval_down_to) {
2913 auto p = Pyramids[level].begin();
2914 ppos = 0;
2915 skip_remaining = false;
2916
2917 #pragma omp parallel for firstprivate(p, ppos) schedule(dynamic)
2918 for (size_t i = 0; i < nrPyramids[level]; i++) {
2919 if (skip_remaining)
2920 continue;
2921 for (; i > ppos; ++ppos, ++p)
2922 ;
2923 for (; i < ppos; --ppos, --p)
2924 ;
2925
2926 if (Done[i])
2927 continue;
2928 Done[i] = 1;
2929
2930 try {
2931 INTERRUPT_COMPUTATION_BY_EXCEPTION
2932
2933 Full_Cone<Integer> Pyramid(*this, *p);
2934 // Pyramid.recursion_allowed=false;
2935 Pyramid.do_all_hyperplanes = false;
2936 if (level >= 2 && do_partial_triangulation) { // limits the descent of do_partial_triangulation
2937 Pyramid.do_triangulation = true;
2938 Pyramid.do_partial_triangulation = false;
2939 }
2940 Pyramid.store_level = level + 1;
2941 Pyramid.build_cone();
2942 if (check_evaluation_buffer_size() || Top_Cone->check_pyr_buffer(level + 1)) {
2943 // interrupt parallel execution to keep the buffer under control
2944 skip_remaining = true;
2945 }
2946 } catch (const std::exception&) {
2947 tmp_exception = std::current_exception();
2948 skip_remaining = true;
2949 #pragma omp flush(skip_remaining)
2950 }
2951 } // end parallel for
2952 if (!(tmp_exception == 0))
2953 std::rethrow_exception(tmp_exception);
2954
2955 // remove done pyramids
2956 p = Pyramids[level].begin();
2957 for (size_t i = 0; p != Pyramids[level].end(); i++) {
2958 if (Done[i]) {
2959 p = Pyramids[level].erase(p);
2960 nrPyramids[level]--;
2961 Done[i] = 0;
2962 }
2963 else {
2964 ++p;
2965 }
2966 }
2967
2968 try_offload(level + 1);
2969
2970 if (check_evaluation_buffer_size()) {
2971 if (verbose)
2972 verboseOutput() << nrPyramids[level] << " pyramids remaining on level " << level << ", ";
2973 Top_Cone->evaluate_triangulation();
2974 try_offload(level + 1);
2975 }
2976
2977 if (Top_Cone->check_pyr_buffer(level + 1)) {
2978 evaluate_stored_pyramids(level + 1);
2979 }
2980
2981 } // end while (nrPyramids[level] > 0)
2982
2983 if (verbose) {
2984 verboseOutput() << "**************************************************" << endl;
2985 verboseOutput() << "all pyramids on level " << level << " done!" << endl;
2986 if (nrPyramids[level + 1] == 0) {
2987 for (size_t l = 0; l <= level; ++l) {
2988 if (nrPyramids[l] > 0) {
2989 verboseOutput() << "level " << l << " pyramids remaining: " << nrPyramids[l] << endl;
2990 }
2991 }
2992 verboseOutput() << "**************************************************" << endl;
2993 }
2994 }
2995 if (check_evaluation_buffer()) {
2996 Top_Cone->evaluate_triangulation();
2997 }
2998
2999 evaluate_stored_pyramids(level + 1);
3000 }
3001
3002 //---------------------------------------------------------------------------
3003
3004 /* builds the cone successively by inserting generators */
3005 template <typename Integer>
build_cone()3006 void Full_Cone<Integer>::build_cone() {
3007 // if(dim>0){ //correction needed to include the 0 cone;
3008
3009 // cout << "Pyr " << pyr_level << endl;
3010
3011 if (start_from == 0)
3012 in_triang = vector<bool>(nr_gen, false);
3013
3014 size_t RecBoundSuppHyp;
3015 RecBoundSuppHyp = dim * SuppHypRecursionFactor;
3016 if (using_GMP<Integer>())
3017 RecBoundSuppHyp *= GMP_time_factor; // pyramid building is more difficult for complicated arithmetic
3018 if (using_renf<Integer>())
3019 RecBoundSuppHyp *= renf_time_factor_pyr * renf_degree * renf_degree;
3020
3021 size_t RecBoundTriang = 1000000; // if number(supphyps)*size(triang) > RecBoundTriang pass to pyramids
3022 if (using_GMP<Integer>())
3023 RecBoundTriang *= GMP_time_factor;
3024 if (using_renf<Integer>())
3025 RecBoundTriang *= renf_time_factor;
3026
3027 tri_recursion = false;
3028
3029 multithreaded_pyramid = (omp_get_level() == omp_start_level);
3030
3031 if (!use_existing_facets) {
3032 if (multithreaded_pyramid) {
3033 HypCounter.resize(omp_get_max_threads());
3034 for (size_t i = 0; i < HypCounter.size(); ++i)
3035 HypCounter[i] = i + 1;
3036 }
3037 else {
3038 HypCounter.resize(1);
3039 HypCounter[0] = 1;
3040 }
3041
3042 find_and_evaluate_start_simplex();
3043 }
3044
3045 long last_to_be_inserted = nr_gen - 1; // because we don't need to compute support hyperplanes in this case
3046 for (int j = nr_gen - 1; j >= 0; --j) {
3047 if (!in_triang[j]) {
3048 last_to_be_inserted = j;
3049 break;
3050 }
3051 } // last_to_be_inserted now determined
3052 if(!is_pyramid)
3053 top_last_to_be_inserted = last_to_be_inserted;
3054
3055 long second_last_to_be_inserted = nr_gen; // indicates: will be disregarded if = nr_gen
3056 if(do_signed_dec && !is_pyramid){
3057 for (int j = last_to_be_inserted - 1; j >= 0; --j) {
3058 if (!in_triang[j]) {
3059 second_last_to_be_inserted = j;
3060 break;
3061 }
3062 } // last_to_be_inserted now determined
3063 }
3064
3065 // cout << "Last " << Top_Cone->top_last_to_be_inserted << " Second " << second_last_to_be_inserted << " nr_gen " << nr_gen << endl;
3066
3067 if(is_pyramid && pyramids_for_last_built_directly) // no higher level pyramids in this case
3068 recursion_allowed = false;
3069
3070 bool is_new_generator;
3071
3072 // RecBoundSuppHyp = 1000; // for tests
3073
3074 for (long i = start_from; i < (long) nr_gen; ++i) {
3075
3076
3077 INTERRUPT_COMPUTATION_BY_EXCEPTION
3078
3079 if(i == last_to_be_inserted && pyramids_for_last_built_directly){
3080 break; // in this case we have all pyramids with apex the last generator to be inserted
3081 }
3082
3083 //time_t start, end;
3084 //time(&start);
3085
3086 start_from = i;
3087
3088 if (in_triang[i])
3089 continue;
3090
3091 if (do_triangulation && TriangulationBufferSize > 2 * RecBoundTriang) // emermergency brake
3092 tri_recursion = true; // to switch off production of simplices in favor
3093 // of non-recursive pyramids
3094 #ifdef NMZ_EXTENDED_TESTS
3095 if(test_small_pyramids)
3096 tri_recursion=true;
3097 #endif
3098 Integer scalar_product;
3099 is_new_generator = false;
3100 auto l = Facets.begin();
3101 old_nr_supp_hyps = Facets.size(); // Facets will be extended in the loop
3102
3103 long long nr_pos = 0, nr_neg = 0;
3104 long long nr_neg_simp = 0, nr_pos_simp = 0;
3105 vector<Integer> L;
3106 std::exception_ptr tmp_exception;
3107
3108 size_t lpos = 0;
3109 #pragma omp parallel for private(L, scalar_product) firstprivate(lpos, l) reduction(+ : nr_pos, nr_neg)
3110 for (size_t k = 0; k < old_nr_supp_hyps; k++) {
3111 try {
3112 for (; k > lpos; lpos++, l++)
3113 ;
3114 for (; k < lpos; lpos--, l--)
3115 ;
3116
3117 L = Generators[i];
3118 scalar_product = v_scalar_product(L, (*l).Hyp);
3119 l->ValNewGen = scalar_product;
3120 l->negative = false;
3121 l->positive = false;
3122 l->neutral = false;
3123 if (scalar_product < 0) {
3124 is_new_generator = true;
3125 l->negative = true;
3126 nr_neg++;
3127 if (l->simplicial)
3128 #pragma omp atomic
3129 nr_neg_simp++;
3130 continue;
3131 }
3132 if (scalar_product == 0) {
3133 l->neutral = true;
3134 continue;
3135 }
3136 // if (scalar_product>0) {
3137 nr_pos++;
3138 l->positive = true;
3139 if (l->simplicial)
3140 #pragma omp atomic
3141 nr_pos_simp++;
3142 //}
3143 } catch (const std::exception&) {
3144 tmp_exception = std::current_exception();
3145 }
3146 } // end parallel for
3147
3148 if (!(tmp_exception == 0))
3149 std::rethrow_exception(tmp_exception);
3150
3151 if (!is_new_generator && !pulling_triangulation)
3152 continue;
3153
3154 // the i-th generator is used in the triangulation
3155 // in_triang[i]=true; // now at end of loop
3156 if (deg1_triangulation && isComputed(ConeProperty::Grading))
3157 deg1_triangulation = (gen_degrees[i] == 1);
3158
3159 if (!omp_in_parallel())
3160 try_offload(0);
3161 /* if(!is_pyramid && verbose )
3162 verboseOutput() << "Neg " << nr_neg << " Pos " << nr_pos << " NegSimp " <<nr_neg_simp << " PosSimp " <<nr_pos_simp <<
3163 endl; */
3164
3165 // First we test whether to go to recursive pyramids because of too many supphyps
3166 if ( ( do_all_hyperplanes || (i != last_to_be_inserted) ) &&
3167 recursion_allowed &&
3168 ( (nr_neg * nr_pos - (nr_neg_simp * nr_pos_simp) >= (long)RecBoundSuppHyp)
3169 #ifdef NMZ_EXTENDED_TESTS
3170 || test_small_pyramids
3171 #endif
3172 )
3173 )
3174 { // use pyramids because of supphyps
3175
3176 if(i == second_last_to_be_inserted)
3177 pyramids_for_last_built_directly = true;
3178 if (do_triangulation)
3179 tri_recursion = true; // We can not go back to classical triangulation
3180 if (check_evaluation_buffer()) {
3181 Top_Cone->evaluate_triangulation();
3182 }
3183
3184 process_pyramids(i, true); // recursive
3185 // lastGen=i;
3186 // nextGen=i+1;
3187 }
3188 else { // now we check whether to go to pyramids because of the size of triangulation
3189 // once we have done so, we must stay with it
3190
3191 if (recursion_allowed && (tri_recursion || (do_triangulation && (nr_neg * TriangulationBufferSize > RecBoundTriang ||
3192 3 * omp_get_max_threads() * TriangulationBufferSize >
3193 EvalBoundTriang))) ) { // go to pyramids because of triangulation
3194 if (check_evaluation_buffer()) {
3195 Top_Cone->evaluate_triangulation();
3196 }
3197
3198 tri_recursion = true;
3199 process_pyramids(i, false); // non-recursive
3200 }
3201 else { // no pyramids necesary or allowed
3202 if (do_partial_triangulation)
3203 process_pyramids(i, false); // non-recursive
3204 if (do_triangulation)
3205 extend_triangulation(i);
3206 }
3207
3208 if (is_new_generator && (do_all_hyperplanes || i != last_to_be_inserted) )
3209 find_new_facets(i);
3210 }
3211 size_t nr_new_facets = Facets.size() - old_nr_supp_hyps;
3212 // time(&end);
3213 /* double dif = difftime (end,start);
3214
3215 if (verbose) {
3216 verboseOutput() << "Generator took " << dif << " sec " <<endl;
3217 }*/
3218
3219 // removing the negative hyperplanes if necessary
3220 if (do_all_hyperplanes || i != last_to_be_inserted) {
3221 l = Facets.begin();
3222 for (size_t j = 0; j < old_nr_supp_hyps; j++) {
3223 if (l->negative) {
3224 l = Facets.erase(l);
3225 }
3226 else
3227 ++l;
3228 }
3229 }
3230
3231 GensInCone.push_back(i);
3232 nrGensInCone++;
3233
3234 Comparisons.push_back(nrTotalComparisons);
3235
3236 in_triang[i] = true;
3237
3238 if (verbose) {
3239 verboseOutput() << "gen=" << i + 1 << ", ";
3240 if (do_all_hyperplanes || i != last_to_be_inserted) {
3241 verboseOutput() << Facets.size() << " hyp, " << nr_new_facets << " new";
3242 }
3243 else {
3244 verboseOutput() << Support_Hyperplanes.nr_of_rows() << " hyp";
3245 }
3246 if (nrPyramids[0] > 0)
3247 verboseOutput() << ", " << nrPyramids[0] << " pyr";
3248 if (do_triangulation || do_partial_triangulation){
3249 size_t trisize;
3250 if(pulling_triangulation)
3251 trisize = TriangulationBuffer.size();
3252 else
3253 trisize = TriangulationBufferSize;
3254 verboseOutput() << ", " << trisize << " simpl";
3255 }
3256 verboseOutput() << endl;
3257 }
3258
3259 } // loop over i
3260
3261 start_from = 0; // in order that we can restart the primal algorithm again
3262
3263 if (is_pyramid && do_all_hyperplanes) // must give supphyps back to mother
3264 Mother->select_supphyps_from(Facets, apex, Mother_Key, in_triang);
3265
3266 INTERRUPT_COMPUTATION_BY_EXCEPTION
3267
3268 // transfer Facets --> SupportHyperplanes
3269 if (do_all_hyperplanes) {
3270 nrSupport_Hyperplanes = Facets.size();
3271 Support_Hyperplanes = Matrix<Integer>(nrSupport_Hyperplanes, 0);
3272 auto IHV = Facets.begin();
3273 for (size_t i = 0; i < nrSupport_Hyperplanes; ++i, ++IHV) {
3274 if (keep_convex_hull_data)
3275 Support_Hyperplanes[i] = IHV->Hyp;
3276 else
3277 swap(Support_Hyperplanes[i], IHV->Hyp);
3278 }
3279 setComputed(ConeProperty::SupportHyperplanes);
3280 }
3281 Support_Hyperplanes.set_nr_of_columns(dim);
3282
3283 if (do_extreme_rays && do_all_hyperplanes && !do_supphyps_dynamic)
3284 compute_extreme_rays(true);
3285
3286 INTERRUPT_COMPUTATION_BY_EXCEPTION
3287
3288 transfer_triangulation_to_top(); // transfer remaining simplices to top
3289 if (check_evaluation_buffer()) {
3290 Top_Cone->evaluate_triangulation();
3291 }
3292
3293 if (!keep_convex_hull_data)
3294 Facets.clear();
3295 }
3296
3297 //---------------------------------------------------------------------------
3298
3299 template <typename Integer>
find_bottom_facets()3300 void Full_Cone<Integer>::find_bottom_facets() {
3301 if (verbose)
3302 verboseOutput() << "Computing bottom decomposition" << endl;
3303
3304 vector<key_t> start_simpl = Generators.max_rank_submatrix_lex();
3305 Order_Vector = vector<Integer>(dim, 0);
3306 for (size_t i = 0; i < dim; ++i)
3307 for (size_t j = 0; j < dim; ++j)
3308 Order_Vector[j] += ((unsigned long)(1 + i % 10)) * Generators[start_simpl[i]][j];
3309
3310 // First the generators for the recession cone = our cone
3311 Matrix<Integer> BottomGen(0, dim + 1);
3312 vector<Integer> help(dim + 1);
3313 for (size_t i = 0; i < nr_gen; ++i) {
3314 for (size_t j = 0; j < dim; ++j)
3315 help[j] = Generators[i][j];
3316 help[dim] = 0;
3317 BottomGen.append(help);
3318 }
3319 // then the same vectors as generators of the bottom polyhedron
3320 for (size_t i = 0; i < nr_gen; ++i) {
3321 for (size_t j = 0; j < dim; ++j)
3322 help[j] = Generators[i][j];
3323 help[dim] = 1;
3324 BottomGen.append(help);
3325 }
3326
3327 Full_Cone BottomPolyhedron(BottomGen);
3328 BottomPolyhedron.verbose = verbose;
3329 BottomPolyhedron.do_extreme_rays = true;
3330 BottomPolyhedron.keep_order = true;
3331 try {
3332 BottomPolyhedron.dualize_cone(); // includes finding extreme rays
3333 } catch (const NonpointedException&) {
3334 };
3335
3336 // transfer pointedness
3337 assert(BottomPolyhedron.isComputed(ConeProperty::IsPointed));
3338 pointed = BottomPolyhedron.pointed;
3339 setComputed(ConeProperty::IsPointed);
3340
3341 // BottomPolyhedron.Support_Hyperplanes.pretty_print(cout);
3342
3343 help.resize(dim);
3344
3345 // find extreme rays of Bottom among the generators
3346 vector<key_t> BottomExtRays;
3347 for (size_t i = 0; i < nr_gen; ++i)
3348 if (BottomPolyhedron.Extreme_Rays_Ind[i + nr_gen])
3349 BottomExtRays.push_back(i);
3350 /* vector<key_t> BottomExtRays; // can be used if the bool vector should not exist anymore
3351 size_t start_search=0;
3352 for(size_t i=0;i<ExtStrahl.nr_of_rows();++i){
3353 if(BottomPolyhedron.ExtStrahl[i][dim]==1){
3354 BottomPolyhedron.ExtStrahl[i].resize(dim);
3355 for(size_t j=0;j<nr_gen;++j){
3356 size_t k=(j+start_search) % nr_gen;
3357 if(BottomPolyhedron.ExtStrahl[i]==Generators[k]){
3358 BottomExtRays.push_back(k);
3359 start_search++;
3360 }
3361 }
3362 }
3363 }*/
3364
3365 if (verbose)
3366 verboseOutput() << "Bottom has " << BottomExtRays.size() << " extreme rays" << endl;
3367
3368 INTERRUPT_COMPUTATION_BY_EXCEPTION
3369
3370 Matrix<Integer> BottomFacets(0, dim);
3371 vector<Integer> BottomDegs(0, static_cast<unsigned long>(dim));
3372 if (!isComputed(ConeProperty::SupportHyperplanes)) {
3373 Support_Hyperplanes = Matrix<Integer>(0, dim);
3374 nrSupport_Hyperplanes = 0;
3375 }
3376 for (size_t i = 0; i < BottomPolyhedron.nrSupport_Hyperplanes; ++i) {
3377 Integer test = BottomPolyhedron.Support_Hyperplanes[i][dim];
3378 for (size_t j = 0; j < dim; ++j)
3379 help[j] = BottomPolyhedron.Support_Hyperplanes[i][j];
3380 if (test == 0 && !isComputed(ConeProperty::SupportHyperplanes)) {
3381 Support_Hyperplanes.append(help);
3382 nrSupport_Hyperplanes++;
3383 }
3384 if (test < 0) {
3385 BottomFacets.append(help);
3386 BottomDegs.push_back(-test);
3387 }
3388 }
3389
3390 setComputed(ConeProperty::SupportHyperplanes);
3391
3392 if (!pointed)
3393 throw NonpointedException();
3394
3395 INTERRUPT_COMPUTATION_BY_EXCEPTION
3396
3397 vector<key_t> facet;
3398 for (size_t i = 0; i < BottomFacets.nr_of_rows(); ++i) {
3399 facet.clear();
3400 for (unsigned int& BottomExtRay : BottomExtRays)
3401 if (v_scalar_product(Generators[BottomExtRay], BottomFacets[i]) == BottomDegs[i])
3402 facet.push_back(BottomExtRay);
3403 Pyramids[0].push_back(facet);
3404 nrPyramids[0]++;
3405 }
3406 if (verbose)
3407 verboseOutput() << "Bottom decomposition computed, " << nrPyramids[0] << " subcones" << endl;
3408 }
3409
3410 template <typename Integer>
start_message()3411 void Full_Cone<Integer>::start_message() {
3412 if (verbose) {
3413 verboseOutput() << "*************************************************************" << endl;
3414 verboseOutput() << "starting full cone computation" << endl;
3415 }
3416 }
3417
3418 template <typename Integer>
end_message()3419 void Full_Cone<Integer>::end_message() {
3420 if (verbose) {
3421 verboseOutput() << "-------------------------------------------------------------" << endl;
3422 }
3423 }
3424
3425 //---------------------------------------------------------------------------
3426
3427 template <typename Integer>
build_cone_dynamic()3428 void Full_Cone<Integer>::build_cone_dynamic() {
3429 Matrix<Integer> OriGens(0,dim);
3430 swap(Generators,OriGens);
3431 bool first=true;
3432 while(true){
3433 size_t nr_extr= OriGens.extreme_points_first(verbose,IntHullNorm);
3434 size_t old_nr_rows = Generators.nr_of_rows();
3435 size_t new_nr_rows = old_nr_rows + nr_extr;
3436 // Generators.resize(new_nr_rows, dim);
3437 for(size_t i=0; i<nr_extr; ++i)
3438 Generators.append(OriGens[i]);
3439 if(first){
3440 if(Generators.rank() < dim){
3441 if(verbose)
3442 verboseOutput() << "Selection of exteme points failed" << endl;
3443 swap(Generators, OriGens);
3444 new_nr_rows=Generators.nr_of_rows();
3445 }
3446 }
3447 for(auto& F: Facets){
3448 F.GenInHyp.resize(new_nr_rows);
3449 }
3450 in_triang.resize(new_nr_rows);
3451
3452 if(!first){
3453 use_existing_facets = true;
3454 start_from = old_nr_rows;
3455 }
3456 first = false;
3457 keep_convex_hull_data = true;
3458 nr_gen = new_nr_rows;
3459 Extreme_Rays_Ind.resize(nr_gen);
3460 build_cone();
3461
3462 if(verbose)
3463 verboseOutput() << "Selecting remaining generators" << endl;
3464 deque<bool> not_contained(OriGens.nr_of_rows(), false);
3465 #pragma omp parallel for
3466 for(size_t i=0; i< OriGens.nr_of_rows(); ++i){
3467 if(!contains(OriGens[i]))
3468 not_contained[i]=true;
3469 }
3470 vector<key_t> selection;
3471 for(size_t i=0; i< OriGens.nr_of_rows(); ++i){
3472 if(not_contained[i])
3473 selection.push_back(i);
3474 }
3475
3476 OriGens = OriGens.submatrix(selection);
3477 if(verbose)
3478 verboseOutput() << OriGens.nr_of_rows() << " old generators remaining" << endl;
3479 if(OriGens.nr_of_rows()==0)
3480 break;
3481 }
3482 compute_extreme_rays(true);
3483 }
3484
3485 //--------------------------------------------------------------------------
3486
3487 template <typename Integer>
make_hollow_triangulation_inner(const vector<size_t> & Selection,const vector<key_t> & PatternKey,const dynamic_bitset & Pattern)3488 size_t Full_Cone<Integer>::make_hollow_triangulation_inner(const vector<size_t>& Selection,
3489 const vector<key_t>& PatternKey, const dynamic_bitset& Pattern){
3490
3491 if(verbose){
3492 verboseOutput() << "Evaluating " << Selection.size() << " simplices ";
3493 if(PatternKey.size() == 0)
3494 verboseOutput() << endl;
3495 else{
3496 vector<key_t> block_start, block_end;
3497 block_start.push_back(PatternKey[0]);
3498 for(size_t k = 1; k< PatternKey.size(); ++k){
3499 if(PatternKey[k] > PatternKey[k-1]+1){
3500 block_end.push_back(PatternKey[k-1]);
3501 block_start.push_back(PatternKey[k]);
3502 }
3503 }
3504 block_end.push_back(PatternKey.back());
3505 verboseOutput() << "for ";
3506 for(size_t k = 0; k < block_start.size(); ++k){
3507 if(block_end[k] == block_start[k])
3508 verboseOutput() << block_end[k] << " ";
3509 else
3510 verboseOutput() << block_start[k] << "-" << block_end[k] << " ";
3511 }
3512 verboseOutput() << endl;
3513 }
3514 }
3515
3516 list<pair<dynamic_bitset,size_t> > Subfacets;
3517 bool restricted = false;
3518 if(PatternKey.size() > 0)
3519 restricted = true;
3520
3521 vector<key_t> NonPattern; // NonPattern is the complement of Pattern before the highest selected gen
3522 if(restricted){
3523 for(size_t i=0; i < PatternKey.back(); ++i){
3524 if(!Pattern[i])
3525 NonPattern.push_back(i);
3526 }
3527 }
3528
3529 size_t nr_tri = Selection.size();
3530
3531 long nr_threads = omp_get_max_threads();
3532 size_t block_size = nr_tri/nr_threads;
3533 block_size++;
3534
3535 vector<list<pair<dynamic_bitset,size_t> > > SubBlock(nr_threads);
3536
3537 int threads_needed = nr_tri/block_size;
3538 if(threads_needed*block_size < nr_tri)
3539 threads_needed++;
3540
3541 bool skip_remaining = false;
3542 std::exception_ptr tmp_exception;
3543
3544 #pragma omp parallel for
3545
3546 for(int q=0; q<threads_needed; ++q){
3547
3548 if(skip_remaining)
3549 continue;
3550
3551 try{
3552 size_t block_start = q*block_size;
3553 if(block_start > nr_tri)
3554 block_start = 0;
3555 size_t block_end = block_start + block_size;
3556 if(block_end > nr_tri)
3557 block_end = nr_tri;
3558
3559 size_t nr_subblocks = (block_end - block_start)/10000;
3560 nr_subblocks ++;
3561
3562 list<pair<dynamic_bitset,size_t> > MiniBlock;
3563 for(size_t k = 0; k < nr_subblocks; ++k){
3564
3565 size_t subblock_start = block_start + k*10000;
3566 size_t subblock_end = subblock_start + 10000;
3567 if(subblock_end > block_end)
3568 subblock_end = block_end;
3569
3570 #pragma omp critical(HOLLOW_PROGRESS)
3571 //if(verbose && nr_subblocks*nr_threads > 100)
3572 // verboseOutput() << "Block " << q+1 << " Subblock " << k+1 << " of " << nr_subblocks << endl;
3573
3574 INTERRUPT_COMPUTATION_BY_EXCEPTION
3575 for(size_t p=subblock_start; p< subblock_end; ++p){
3576 size_t pp =Selection[p];
3577 if(!restricted){
3578 for(size_t j = 0 ; j < nr_gen; ++j){ // we make copies in which we delete
3579 if(Triangulation_ind[pp].first[j] == 1){ // one entry each
3580 MiniBlock.push_back(make_pair(Triangulation_ind[pp].first,pp)); // nr_done serves as a signature
3581 MiniBlock.back().first[j] = 0; // that allows us to recognize subfacets
3582 } // that arise from the same simplex in T
3583 }
3584 }
3585 else{
3586 bool done = false;
3587 for(size_t j = 0; j< NonPattern.size(); ++j){
3588 if(Triangulation_ind[pp].first[NonPattern[j]]){
3589 MiniBlock.push_back(make_pair(Triangulation_ind[pp].first,pp));
3590 MiniBlock.back().first[NonPattern[j]] = 0;
3591 done = true;
3592 break;
3593 }
3594 }
3595
3596 if(done)
3597 continue;
3598
3599 for(size_t j = PatternKey.back()+1; j < nr_gen; ++j){
3600 if(Triangulation_ind[pp].first[j] == 1){
3601 MiniBlock.push_back(make_pair(Triangulation_ind[pp].first,pp));
3602 MiniBlock.back().first[j] = 0;
3603 // cout << "+++Pattern " << j << endl;
3604 }
3605 }
3606 }
3607 }
3608 remove_twins_in_first(MiniBlock);
3609 SubBlock[q].merge(MiniBlock);
3610 remove_twins_in_first(SubBlock[q],true);
3611 }
3612
3613 remove_twins_in_first(SubBlock[q],true);
3614
3615 } catch (const std::exception&) {
3616 tmp_exception = std::current_exception();
3617 skip_remaining = true;
3618 #pragma omp flush(skip_remaining)
3619 }
3620 }
3621 if (!(tmp_exception == 0))
3622 std::rethrow_exception(tmp_exception);
3623
3624 int step =2;
3625 bool merged = true;
3626 skip_remaining = false;
3627 while(merged){
3628 merged = false;
3629 //if(verbose && Selection.size() > 200000)
3630 // verboseOutput() << "Merging hollow triangulation, step size " << step << endl;
3631 #pragma omp parallel for
3632 for(int k=0; k < nr_threads; k+=step){
3633
3634 if(skip_remaining)
3635 continue;
3636 try{
3637
3638 INTERRUPT_COMPUTATION_BY_EXCEPTION
3639
3640 if(nr_threads > k + step/2){
3641 SubBlock[k].merge(SubBlock[k+ step/2]);
3642 merged = true;
3643 }
3644 } catch (const std::exception&) {
3645 tmp_exception = std::current_exception();
3646 skip_remaining = true;
3647 #pragma omp flush(skip_remaining)
3648 }
3649 }
3650 if (!(tmp_exception == 0))
3651 std::rethrow_exception(tmp_exception);
3652 step *=2;
3653 }
3654 Subfacets.swap(SubBlock[0]);
3655 remove_twins_in_first(Subfacets, true);
3656
3657 size_t nr_subfacets = Subfacets.size();
3658
3659 for(auto F = Subfacets.begin(); F!=Subfacets.end(); ){ // encode subfacets as a single bitset associated to
3660 size_t s = F->second; // simplex
3661 dynamic_bitset diff = Triangulation_ind[s].first;
3662 diff -= F->first;
3663 Triangulation_ind[s].second |= diff;
3664 F = Subfacets.erase(F);
3665 }
3666
3667 return nr_subfacets;
3668 }
3669
3670 //--------------------------------------------------------------------------
3671 template <typename Integer>
refine_and_process_selection(vector<size_t> & Selection,const vector<key_t> & PatternKey,const dynamic_bitset & Pattern,size_t & nr_subfacets)3672 size_t Full_Cone<Integer>::refine_and_process_selection(vector<size_t>& Selection,
3673 const vector<key_t>& PatternKey, const dynamic_bitset& Pattern, size_t& nr_subfacets){
3674
3675 vector<size_t > Refinement;
3676 key_t select_gen = PatternKey.back();
3677
3678 vector<key_t> NonPattern;
3679 for(size_t i=0; i < PatternKey.back(); ++i){
3680 if(!Pattern[i])
3681 NonPattern.push_back(i);
3682 }
3683
3684 dynamic_bitset TwoInNonPattern(Selection.size());
3685 for(size_t i=0; i<Selection.size(); ++i){ // At all places in PatternKey we want a 1
3686 if(!Triangulation_ind[Selection[i]].first[select_gen]) // and at most one more before
3687 continue; // the largest entry in PatternKey
3688 size_t nr_ones = 0;
3689 bool good = true;
3690 for(size_t j=0; j < NonPattern.size(); ++j){
3691 if(Triangulation_ind[Selection[i]].first[NonPattern[j]])
3692 nr_ones++;
3693 if(nr_ones > 1){
3694 TwoInNonPattern[i] = 1;
3695 good = false;
3696 break;
3697 }
3698 }
3699 if(good)
3700 Refinement.push_back(Selection[i]);
3701 }
3702
3703 if(Refinement.size() >= HollowTriBound
3704 #ifdef NMZ_EXTENDED_TESTS
3705 || (test_small_pyramids && Refinement.size() >= 10)
3706 #endif
3707 )
3708 extend_selection_pattern(Refinement,PatternKey,Pattern, nr_subfacets);
3709 else{
3710 if(Refinement.size() > 0){
3711 // struct timeval begin, end;
3712 // gettimeofday(&begin, 0);
3713 nr_subfacets += make_hollow_triangulation_inner(Refinement,PatternKey,Pattern);
3714 /* gettimeofday(&end, 0);
3715 long seconds = end.tv_sec - begin.tv_sec;
3716 long microseconds = end.tv_usec - begin.tv_usec;
3717 double elapsed = seconds + microseconds*1e-6;
3718 printf("Time measured: %.3f seconds.\n", elapsed); */
3719 }
3720 }
3721
3722 vector<size_t> NewSelection;
3723 for(size_t i = 0; i< Selection.size();++i){
3724 if(!TwoInNonPattern[i])
3725 NewSelection.push_back(Selection[i]);
3726 }
3727 // cout << "Sieving " << Selection.size() << " -- " << NewSelection.size() << endl;
3728 swap(Selection, NewSelection);
3729
3730 return nr_subfacets;
3731 }
3732
3733 //--------------------------------------------------------------------------
3734 template <typename Integer>
extend_selection_pattern(vector<size_t> & Selection,const vector<key_t> & PatternKey,const dynamic_bitset & Pattern,size_t & nr_subfacets)3735 size_t Full_Cone<Integer>::extend_selection_pattern(vector<size_t>& Selection,
3736 const vector<key_t>& PatternKey, const dynamic_bitset& Pattern, size_t& nr_subfacets){
3737
3738 if(Selection.size() == 0)
3739 return nr_subfacets;
3740
3741 size_t start_gen;
3742 if(PatternKey.size() == 0)
3743 start_gen = 0;
3744 else
3745 start_gen = PatternKey.back()+1;
3746
3747 int total_nr_gaps = nr_gen - dim +1 ; // in a subfacet
3748 int gaps_already = (start_gen+1) - PatternKey.size();
3749 gaps_already--; // one of the non-pattern places can be set. We stay on the safe size
3750 int nr_further_gaps = total_nr_gaps - gaps_already;
3751 size_t last_gen = start_gen + nr_further_gaps +1;
3752 if(last_gen >= nr_gen)
3753 last_gen = nr_gen-1;
3754
3755 for(size_t i=start_gen; i <= last_gen; ++i){
3756
3757 vector<key_t> PatternKeyRefinement = PatternKey;
3758 PatternKeyRefinement.push_back(i);
3759
3760 dynamic_bitset PatternRefinement = Pattern;
3761 PatternRefinement[i] = 1;
3762 if(verbose){
3763 vector<key_t> block_start, block_end;
3764 block_start.push_back(PatternKeyRefinement[0]);
3765 for(size_t k = 1; k< PatternKeyRefinement.size(); ++k){
3766 if(PatternKeyRefinement[k] > PatternKeyRefinement[k-1]+1){
3767 block_end.push_back(PatternKeyRefinement[k-1]);
3768 block_start.push_back(PatternKeyRefinement[k]);
3769 }
3770 }
3771 block_end.push_back(PatternKeyRefinement.back());
3772 verboseOutput() << "Select ";
3773 for(size_t k = 0; k < block_start.size(); ++k){
3774 if(block_end[k] == block_start[k])
3775 verboseOutput() << block_end[k] << " ";
3776 else
3777 verboseOutput() << block_start[k] << "-" << block_end[k] << " ";
3778 }
3779 verboseOutput() << endl;
3780 }
3781
3782 refine_and_process_selection(Selection, PatternKeyRefinement, PatternRefinement, nr_subfacets);
3783
3784 if(Selection.size() == 0)
3785 return nr_subfacets;
3786 }
3787
3788 return nr_subfacets;
3789 }
3790
3791 //--------------------------------------------------------------------------
3792 template <typename Integer>
make_hollow_triangulation()3793 size_t Full_Cone<Integer>::make_hollow_triangulation(){
3794
3795 vector<key_t> PatternKey;
3796 dynamic_bitset Pattern(nr_gen);
3797 size_t nr_subfacets = 0;
3798
3799 for(auto& T:Triangulation_ind)
3800 T.second.resize(nr_gen);
3801
3802 vector<size_t> All(Triangulation_ind.size());
3803 for(size_t i=0; i< All.size(); ++i)
3804 All[i] = i;
3805
3806 if(Triangulation_ind.size() < HollowTriBound)
3807 nr_subfacets = make_hollow_triangulation_inner(All,PatternKey,Pattern);
3808 else
3809 extend_selection_pattern(All,PatternKey,Pattern, nr_subfacets);
3810
3811 return nr_subfacets;
3812 }
3813 //--------------------------------------------------------------------------
3814
3815 template <typename Integer>
compute_multiplicity_or_integral_by_signed_dec()3816 void Full_Cone<Integer>::compute_multiplicity_or_integral_by_signed_dec() {
3817
3818 // assert(isComputed(ConeProperty::Triangulation));
3819
3820 // for(auto& T: Triangulation)
3821 // Triangulation_ind.push_back(key_to_bitset(T.key, nr_gen));
3822
3823 if(verbose)
3824 verboseOutput() << "Computing by signaed decomposition" << endl;
3825
3826 if(verbose)
3827 verboseOutput() << "Making hollow triangulation" << endl;
3828
3829
3830 size_t nr_subfacets = make_hollow_triangulation();
3831
3832 if(verbose)
3833 verboseOutput() << "Size of triangulation " << Triangulation_ind.size() << endl;
3834 if(verbose)
3835 verboseOutput() << "Size of hollow triangulation " << nr_subfacets << endl;
3836
3837 vector<key_t> FirstSimplex = Generators.max_rank_submatrix_lex();
3838
3839 Matrix<mpz_class> Generators_mpz(nr_gen,dim);
3840 convert(Generators_mpz, Generators);
3841
3842 vector<mpz_class> GradingOnPrimal_mpz;
3843 convert(GradingOnPrimal_mpz, GradingOnPrimal);
3844
3845 size_t nr_attempts = 0;
3846 vector<long> Powers10(15);
3847 Powers10[0] = 1;
3848 for(size_t i=1; i < Powers10.size(); i++){
3849 Powers10[i] = 3 * Powers10[i-1];
3850 }
3851
3852 vector<mpz_class> add_vec;
3853 long rand_module = 107;
3854 vector<Integer> Dummy;
3855
3856 Matrix<mpz_class> CandidatesGeneric_mpz(2,dim);
3857 Matrix<Integer> CandidatesGeneric(2,dim);
3858 vector<mpz_class> Generic_mpz;
3859
3860 if(verbose)
3861 verboseOutput() << "Trying to find geric vector" << endl;
3862
3863 // We exchange the roles of the generic vector v and the grading.
3864 // This is possible since one must avoid that they span the same hyperplane
3865 // over a subfacet of the hollow triangulation if and only if the choice of our vector
3866 // is non-generic. This is a symmetric relation: grading generic for v <===> v generic for grading.
3867
3868 bool use_mpz = using_GMP<Integer>();
3869
3870 while(true){
3871 nr_attempts++;
3872
3873 if(nr_attempts > Powers10.size())
3874 throw NotComputableException("SinedDec given up since generaic verctor could not be found");
3875
3876 for(size_t k=0; k<2; ++k){
3877 for(size_t i=0;i< dim;++i){
3878 add_vec = Generators_mpz[FirstSimplex[i]];
3879 long fact_1 = 1 + rand() % rand_module;
3880 long fact_2 = rand() % rand_module;
3881 mpz_class fact = convertTo<mpz_class>(fact_1);
3882 fact *= Powers10[nr_attempts - 1];
3883 fact += fact_2;
3884 v_scalar_multiplication(add_vec, fact);
3885 CandidatesGeneric_mpz[k] = v_add(CandidatesGeneric_mpz[k], add_vec);
3886 }
3887 }
3888
3889 if(!use_mpz){
3890 try{
3891 convert(CandidatesGeneric,CandidatesGeneric_mpz);
3892 } catch (const ArithmeticException& e) {
3893 use_mpz = true;
3894 }
3895 }
3896
3897 bool found_generic = false;
3898
3899 if(!use_mpz){
3900 SignedDec<Integer> SDGen(Triangulation_ind, Generators, GradingOnPrimal, omp_start_level);
3901 SDGen.verbose = verbose;
3902 SDGen.CandidatesGeneric = CandidatesGeneric;
3903 SDGen.Generic = GradingOnPrimal; // for the first round
3904
3905 try{
3906 if(SDGen.FindGeneric()){ // found a generic vector
3907 vector<Integer> Generic_Integer = SDGen.GenericComputed;
3908 found_generic = true;
3909 convert(Generic_mpz,Generic_Integer);
3910 }
3911 } catch (const ArithmeticException& e) {
3912 if(verbose)
3913 verboseOutput() << "******** Overflow in search for generic vector. I repeat with mpz_class. ********" << endl;
3914 use_mpz = true;
3915 }
3916 }
3917 if(use_mpz){
3918 SignedDec<mpz_class> SDGen(Triangulation_ind, Generators_mpz, GradingOnPrimal_mpz, omp_start_level);
3919 SDGen.verbose = verbose;
3920 SDGen.CandidatesGeneric = CandidatesGeneric_mpz;
3921 SDGen.Generic = GradingOnPrimal_mpz; // for the first round
3922
3923 if(SDGen.FindGeneric()){ // found a generic vector
3924 Generic_mpz = SDGen.GenericComputed;
3925 found_generic = true;
3926 }
3927
3928 }
3929
3930 if(found_generic)
3931 break;
3932 }
3933
3934 v_make_prime(Generic_mpz);
3935
3936 if(block_size_hollow_tri >0){
3937
3938 string file_name = project_name+".basic.data";
3939 ofstream out(file_name.c_str());
3940
3941 out << "Project " << project_name << endl;
3942 out << "Dim " << dim << endl << endl;
3943 out << "Gen " << Generators_mpz.nr_of_rows() << endl;
3944 Generators_mpz.pretty_print(out);
3945 out << endl;
3946 out << "Grad " << endl;
3947 out << GradingOnPrimal_mpz << endl;
3948 out << "Generic " << endl;
3949 out << Generic_mpz << endl;
3950
3951 cout << "Generic " << endl;
3952 cout << Generic_mpz << endl;
3953
3954 size_t nr_blocks = Triangulation_ind.size()/block_size_hollow_tri;
3955 if(Triangulation_ind.size() % block_size_hollow_tri > 0)
3956 nr_blocks++;
3957 out << "Blocks " << nr_blocks << endl;
3958
3959 for(size_t i=0;i<nr_blocks; ++i){
3960 size_t block_start = i*block_size_hollow_tri;
3961 size_t block_end = block_start + block_size_hollow_tri;
3962 if(block_end > Triangulation_ind.size())
3963 block_end = Triangulation_ind.size();
3964 out << i << " " << block_start << " " << block_end << endl;
3965
3966 }
3967 out.close();
3968
3969 // Before we write the blocks, the simplices are scrambled in order to
3970 // get more homogeneous computation times.
3971 size_t nr_tri = Triangulation_ind.size();
3972 for(size_t i = 0; i < nr_tri; ++i){
3973 size_t j = rand() & nr_tri;
3974 size_t k = rand() % nr_tri;
3975 std::swap(Triangulation_ind[j],Triangulation_ind[k]);
3976 }
3977
3978 bool skip_remaining = false;
3979 std::exception_ptr tmp_exception;
3980
3981 #pragma omp parallel for
3982 for(size_t i=0;i<nr_blocks; ++i){
3983
3984 if(skip_remaining)
3985 continue;
3986 try{
3987 size_t block_start = i*block_size_hollow_tri;
3988 size_t block_end = block_start + block_size_hollow_tri;
3989 if(block_end > Triangulation_ind.size())
3990 block_end = Triangulation_ind.size();
3991 string file_name = project_name+".hollow_tri.";
3992 file_name += to_string(i);
3993 ofstream tri_out(file_name.c_str());
3994 tri_out << "Project " << project_name << endl;
3995 tri_out << "Block " << i << endl << endl;
3996 for(size_t j = block_start; j < block_end; ++j){
3997 tri_out << Triangulation_ind[j].first << " " << Triangulation_ind[j].second << endl;
3998 }
3999 tri_out << "End" << endl;
4000 tri_out.close();
4001 string command = "gzip "+ file_name;
4002 int dummy = system(command.c_str());
4003 if(dummy > 0)
4004 throw NotComputableException("gzip can't be called");
4005 }catch(const std::exception&) {
4006 tmp_exception = std::current_exception();
4007 skip_remaining = true;
4008 #pragma omp flush(skip_remaining)
4009 }
4010 }
4011 if (!(tmp_exception == 0))
4012 std::rethrow_exception(tmp_exception);
4013
4014 if(verbose)
4015 verboseOutput() << "Blocks of hollow triangulation written" << endl;
4016 throw InterruptException("");
4017 }
4018
4019
4020 if(do_integral_by_signed_dec || do_virtual_multiplicity_by_signed_dec){
4021
4022 SignedDec<mpz_class> SDInt(Triangulation_ind, Generators_mpz, GradingOnPrimal_mpz, omp_start_level);
4023 SDInt.size_hollow_triangulation = nr_subfacets;
4024 SDInt.verbose = verbose;
4025 SDInt.Generic = Generic_mpz;
4026 SDInt.Polynomial = Polynomial;
4027 SDInt.dim = dim;
4028 SDInt.decimal_digits = decimal_digits;
4029 convert(SDInt.Embedding, Embedding);
4030
4031 if(do_integral_by_signed_dec){
4032 if(verbose)
4033 verboseOutput()<< "Computing integral" << endl;
4034 if(!SDInt.ComputeIntegral(false)) // no virtual multiplicity
4035 assert(false);
4036 Integral = SDInt.Integral;
4037 DegreeOfPolynomial = SDInt.DegreeOfPolynomial;
4038 RawEuclideanIntegral = SDInt.RawEuclideanIntegral;
4039 setComputed(ConeProperty::Integral);
4040 }
4041
4042 if(do_virtual_multiplicity_by_signed_dec){
4043 if(verbose)
4044 verboseOutput()<< "Computing virtual multiplicity" << endl;
4045 if(!SDInt.ComputeIntegral(true)) // with virtual multiplicity
4046 assert(false);
4047 VirtualMultiplicity = SDInt.VirtualMultiplicity;
4048 DegreeOfPolynomial = SDInt.DegreeOfPolynomial;
4049 setComputed(ConeProperty::VirtualMultiplicity);
4050 }
4051 }
4052
4053 if(!do_multiplicity_by_signed_dec)
4054 return;
4055
4056 if(verbose)
4057 verboseOutput()<< "Computing multiplicity" << endl;
4058
4059 if(!use_mpz){
4060 SignedDec<Integer> SDMult(Triangulation_ind, Generators, GradingOnPrimal, omp_start_level);
4061 SDMult.verbose = verbose;
4062 SDMult.decimal_digits = decimal_digits;
4063 vector<Integer> Generic;
4064 convert(Generic,Generic_mpz);
4065 SDMult.Generic = Generic; // for the first round
4066
4067 try{
4068 if(SDMult.ComputeMultiplicity()){ // found a generic vector
4069 multiplicity = SDMult.multiplicity;
4070 }
4071 else
4072 assert(false);
4073 } catch (const ArithmeticException& e) {
4074 if(verbose)
4075 verboseOutput() << "******** Overflow in computation of multiplicity. I repeat with mpz_class. ********" << endl;
4076 use_mpz = true;
4077 }
4078 }
4079 if(use_mpz){
4080 SignedDec<mpz_class> SDMult(Triangulation_ind, Generators_mpz, GradingOnPrimal_mpz, omp_start_level);
4081 SDMult.verbose = verbose;
4082 SDMult.decimal_digits = decimal_digits;
4083 SDMult.Generic = Generic_mpz;
4084 if(!SDMult.ComputeMultiplicity())
4085 assert(false);
4086 multiplicity = SDMult.multiplicity;
4087 }
4088
4089 Integer corr_factorInteger = v_gcd(GradingOnPrimal); // search in code for corr_factor to find an explanation
4090 mpz_class corr_factor = convertTo<mpz_class>(corr_factorInteger);
4091 multiplicity *= corr_factor;
4092 setComputed(ConeProperty::Multiplicity);
4093 }
4094
4095 template <>
compute_multiplicity_or_integral_by_signed_dec()4096 void Full_Cone<renf_elem_class>::compute_multiplicity_or_integral_by_signed_dec() {
4097
4098 assert(false);
4099 }
4100 //---------------------------------------------------------------------------
4101
4102 template <typename Integer>
build_top_cone()4103 void Full_Cone<Integer>::build_top_cone() {
4104 primal_algorithm_initialize();
4105
4106 if (dim == 0)
4107 return;
4108
4109 if(do_supphyps_dynamic){
4110 build_cone_dynamic();
4111 return;
4112 }
4113
4114 OldCandidates.verbose = verbose;
4115 NewCandidates.verbose = verbose;
4116
4117 if ((!do_bottom_dec || deg1_generated || dim == 1 || (!do_triangulation && !do_partial_triangulation))) {
4118 build_cone();
4119 }
4120 else {
4121 find_bottom_facets();
4122 start_from = nr_gen;
4123 deg1_triangulation = false;
4124
4125 vector<list<vector<key_t>>::iterator> level0_order;
4126 level0_order.reserve(nrPyramids[0]);
4127 auto p = Pyramids[0].begin();
4128 for (size_t k = 0; k < nrPyramids[0]; ++k, ++p) {
4129 level0_order.push_back(p);
4130 }
4131 for (size_t k = 0; k < 5 * nrPyramids[0]; ++k) {
4132 swap(level0_order[rand() % nrPyramids[0]], level0_order[rand() % nrPyramids[0]]);
4133 }
4134 list<vector<key_t>> new_order;
4135 for (size_t k = 0; k < nrPyramids[0]; ++k) {
4136 new_order.push_back(*level0_order[k]);
4137 }
4138 Pyramids[0].clear();
4139 Pyramids[0].splice(Pyramids[0].begin(), new_order);
4140 }
4141
4142 // try_offload(0); // superfluous since tried immediately in evaluate_stored_pyramids(0)
4143
4144 evaluate_stored_pyramids(0); // force evaluation of remaining pyramids
4145
4146 #ifdef NMZ_MIC_OFFLOAD
4147 if (_Offload_get_device_number() < 0) // dynamic check for being on CPU (-1)
4148 {
4149 evaluate_stored_pyramids(0); // previous run could have left over pyramids
4150 mic_offloader.evaluate_triangulation();
4151 }
4152 #endif // NMZ_MIC_OFFLOAD
4153
4154 }
4155
4156 //---------------------------------------------------------------------------
4157
4158 template <typename Integer>
check_evaluation_buffer()4159 bool Full_Cone<Integer>::check_evaluation_buffer() {
4160 return (omp_get_level() == omp_start_level && check_evaluation_buffer_size());
4161 }
4162
4163 //---------------------------------------------------------------------------
4164
4165 template <typename Integer>
check_evaluation_buffer_size()4166 bool Full_Cone<Integer>::check_evaluation_buffer_size() {
4167 return (!Top_Cone->keep_triangulation && Top_Cone->TriangulationBufferSize > EvalBoundTriang);
4168 }
4169
4170 //---------------------------------------------------------------------------
4171
4172 template <typename Integer>
transfer_triangulation_to_top()4173 void Full_Cone<Integer>::transfer_triangulation_to_top() {
4174 size_t i;
4175
4176 // cout << "Pyr level " << pyr_level << endl;
4177
4178 if (!is_pyramid) { // we are in top cone
4179 if (check_evaluation_buffer()) {
4180 evaluate_triangulation();
4181 }
4182 return; // no transfer necessary
4183 }
4184
4185 // now we are in a pyramid
4186
4187 // cout << "In pyramid " << endl;
4188 int tn = 0;
4189 if (omp_in_parallel())
4190 tn = omp_get_ancestor_thread_num(omp_start_level + 1);
4191
4192 auto pyr_simp = TriangulationBuffer.begin();
4193 while (pyr_simp != TriangulationBuffer.end()) {
4194 if (pyr_simp->height == 0) { // it was marked to be skipped
4195 Top_Cone->FS[tn].splice(Top_Cone->FS[tn].end(), TriangulationBuffer, pyr_simp++);
4196 --TriangulationBufferSize;
4197 }
4198 else {
4199 for (i = 0; i < dim; i++) // adjust key to topcone generators
4200 pyr_simp->key[i] = Top_Key[pyr_simp->key[i]];
4201 sort(pyr_simp->key.begin(), pyr_simp->key.end());
4202 ++pyr_simp;
4203 }
4204 }
4205
4206 // cout << "Keys transferred " << endl;
4207 #pragma omp critical(TRIANG)
4208 {
4209 Top_Cone->TriangulationBuffer.splice(Top_Cone->TriangulationBuffer.end(), TriangulationBuffer);
4210 Top_Cone->TriangulationBufferSize += TriangulationBufferSize;
4211 }
4212 TriangulationBufferSize = 0;
4213 }
4214
4215 //---------------------------------------------------------------------------
4216 template <typename Integer>
get_supphyps_from_copy(bool from_scratch,bool with_extreme_rays)4217 void Full_Cone<Integer>::get_supphyps_from_copy(bool from_scratch, bool with_extreme_rays) {
4218 if (isComputed(ConeProperty::SupportHyperplanes)) { // we have them already
4219 if (with_extreme_rays)
4220 compute_extreme_rays();
4221 return;
4222 }
4223
4224 Full_Cone copy((*this).Generators);
4225 copy.verbose = verbose;
4226 if (!from_scratch) {
4227 copy.start_from = start_from;
4228 copy.use_existing_facets = true;
4229 copy.keep_order = true;
4230 copy.HypCounter = HypCounter;
4231 copy.Extreme_Rays_Ind = Extreme_Rays_Ind;
4232 copy.in_triang = in_triang;
4233 copy.old_nr_supp_hyps = old_nr_supp_hyps;
4234 if (isComputed(ConeProperty::ExtremeRays)) {
4235 copy.setComputed(ConeProperty::ExtremeRays);
4236 with_extreme_rays = false;
4237 }
4238 copy.GensInCone = GensInCone;
4239 copy.nrGensInCone = nrGensInCone;
4240 copy.Comparisons = Comparisons;
4241 if (!Comparisons.empty())
4242 copy.nrTotalComparisons = Comparisons[Comparisons.size() - 1];
4243
4244 typename list<FACETDATA<Integer>>::const_iterator l = Facets.begin();
4245
4246 for (size_t i = 0; i < old_nr_supp_hyps; ++i) {
4247 copy.Facets.push_back(*l);
4248 ++l;
4249 }
4250 }
4251
4252 copy.dualize_cone();
4253 if (with_extreme_rays) {
4254 copy.do_extreme_rays = true;
4255 copy.compute();
4256 Extreme_Rays_Ind = copy.Extreme_Rays_Ind;
4257 setComputed(ConeProperty::ExtremeRays);
4258 }
4259
4260 std::swap(Support_Hyperplanes, copy.Support_Hyperplanes);
4261 nrSupport_Hyperplanes = copy.nrSupport_Hyperplanes;
4262 setComputed(ConeProperty::SupportHyperplanes);
4263 do_all_hyperplanes = false;
4264 }
4265
4266 //---------------------------------------------------------------------------
4267
4268 template <typename Integer>
update_reducers(bool forced)4269 void Full_Cone<Integer>::update_reducers(bool forced) {
4270 if ((!do_Hilbert_basis || do_module_gens_intcl) && !forced)
4271 return;
4272
4273 if (NewCandidates.Candidates.empty())
4274 return;
4275
4276 INTERRUPT_COMPUTATION_BY_EXCEPTION
4277
4278 if (hilbert_basis_rec_cone_known) {
4279 NewCandidates.sort_by_deg();
4280 NewCandidates.reduce_by(HBRC);
4281 ModuleGensDepot.merge(NewCandidates);
4282 return;
4283 }
4284
4285 if (nr_gen == dim) // no global reduction in the simplicial case
4286 NewCandidates.sort_by_deg();
4287 if (nr_gen != dim || forced) { // global reduction in the nonsimplicial case (or forced)
4288 NewCandidates.auto_reduce();
4289 if (verbose) {
4290 verboseOutput() << "reducing " << OldCandidates.Candidates.size() << " candidates by "
4291 << NewCandidates.Candidates.size() << " reducers" << endl;
4292 }
4293 OldCandidates.reduce_by(NewCandidates);
4294 }
4295 OldCandidates.merge(NewCandidates);
4296 CandidatesSize = OldCandidates.Candidates.size();
4297 }
4298
4299 //---------------------------------------------------------------------------
4300
4301 template <typename Integer>
prepare_old_candidates_and_support_hyperplanes()4302 void Full_Cone<Integer>::prepare_old_candidates_and_support_hyperplanes() {
4303 if (!isComputed(ConeProperty::SupportHyperplanes)) {
4304 if (verbose) {
4305 verboseOutput() << "**** Computing support hyperplanes for reduction:" << endl;
4306 }
4307 get_supphyps_from_copy(false);
4308 }
4309
4310 check_pointed();
4311 if (!pointed) {
4312 throw NonpointedException();
4313 }
4314
4315 int max_threads = omp_get_max_threads();
4316 size_t Memory_per_gen = 8 * nrSupport_Hyperplanes;
4317 size_t max_nr_gen = RAM_Size / (Memory_per_gen * max_threads);
4318 // cout << "max_nr_gen " << max_nr_gen << endl;
4319 AdjustedReductionBound = max_nr_gen;
4320 if (AdjustedReductionBound < 2000)
4321 AdjustedReductionBound = 2000;
4322
4323 Sorting = compute_degree_function();
4324
4325 bool save_do_module_gens_intcl = do_module_gens_intcl;
4326 do_module_gens_intcl = false; // to avoid multiplying sort_deg by 2 for the original generators
4327 // sort_deg of new candiadtes will be multiplied by 2
4328 // so that all old candidates are tested for reducibility
4329 for (size_t i = 0; i < nr_gen; i++) {
4330 // cout << gen_levels[i] << " ** " << Generators[i];
4331 if (!inhomogeneous || gen_levels[i] == 0 || (!save_do_module_gens_intcl && gen_levels[i] <= 1)) {
4332 OldCandidates.Candidates.push_back(Candidate<Integer>(Generators[i], *this));
4333 OldCandidates.Candidates.back().original_generator = true;
4334 }
4335 }
4336 for (size_t i = 0; i < HilbertBasisRecCone.nr_of_rows(); ++i) {
4337 HBRC.Candidates.push_back(Candidate<Integer>(HilbertBasisRecCone[i], *this));
4338 }
4339 do_module_gens_intcl = save_do_module_gens_intcl; // restore
4340 if (HilbertBasisRecCone.nr_of_rows() > 0) { // early enough to avoid multiplictaion of sort_deg by 2 for the elements
4341 // in HilbertBasisRecCone
4342 hilbert_basis_rec_cone_known = true;
4343 HBRC.sort_by_deg();
4344 }
4345 if (!do_module_gens_intcl) // if do_module_gens_intcl we don't want to change the original monoid
4346 OldCandidates.auto_reduce();
4347 else
4348 OldCandidates.sort_by_deg();
4349 }
4350
4351 //---------------------------------------------------------------------------
4352
4353 template <typename Integer>
evaluate_triangulation()4354 void Full_Cone<Integer>::evaluate_triangulation() {
4355 // prepare reduction
4356 if (do_Hilbert_basis && OldCandidates.Candidates.empty()) {
4357 prepare_old_candidates_and_support_hyperplanes();
4358 }
4359
4360 if (TriangulationBufferSize == 0)
4361 return;
4362
4363 assert(omp_get_level() == omp_start_level);
4364
4365 if(pulling_triangulation)
4366 TriangulationBufferSize = TriangulationBuffer.size(); // the bookkeeping does not work in this case
4367
4368 const long VERBOSE_STEPS = 50;
4369 long step_x_size = TriangulationBufferSize - VERBOSE_STEPS;
4370 if (verbose) {
4371 verboseOutput() << "evaluating " << TriangulationBufferSize << " simplices" << endl;
4372 /* verboseOutput() << "---------+---------+---------+---------+---------+"
4373 << " (one | per 2%)" << endl;*/
4374 }
4375
4376 totalNrSimplices += TriangulationBufferSize;
4377
4378 if (do_Stanley_dec || keep_triangulation) { // in these cases sorting is necessary
4379 for (auto& simp : TriangulationBuffer)
4380 sort(simp.key.begin(), simp.key.end());
4381 }
4382
4383 if (do_evaluation && !do_only_multiplicity) {
4384 deque<bool> done(TriangulationBufferSize, false);
4385 bool skip_remaining;
4386 std::exception_ptr tmp_exception;
4387
4388 do { // allows multiple run of loop below in case of interruption for the update of reducers
4389
4390 skip_remaining = false;
4391 step_x_size = TriangulationBufferSize - VERBOSE_STEPS;
4392
4393 #pragma omp parallel
4394 {
4395 auto s = TriangulationBuffer.begin();
4396 size_t spos = 0;
4397 int tn = omp_get_thread_num();
4398 #pragma omp for schedule(dynamic) nowait
4399 for (size_t i = 0; i < TriangulationBufferSize; i++) {
4400 try {
4401 if (skip_remaining)
4402 continue;
4403
4404 for (; i > spos; ++spos, ++s)
4405 ;
4406 for (; i < spos; --spos, --s)
4407 ;
4408
4409 INTERRUPT_COMPUTATION_BY_EXCEPTION
4410
4411 if (done[spos])
4412 continue;
4413
4414 done[spos] = true;
4415
4416 /* if(keep_triangulation || do_Stanley_dec) -- now done above
4417 sort(s->key.begin(),s->key.end()); */
4418 if (!SimplexEval[tn].evaluate(*s)) {
4419 #pragma omp critical(LARGESIMPLEX)
4420 LargeSimplices.push_back(SimplexEval[tn]);
4421 }
4422 if (verbose) {
4423 #pragma omp critical(VERBOSE)
4424 while ((long)(i * VERBOSE_STEPS) >= step_x_size) {
4425 step_x_size += TriangulationBufferSize;
4426 verboseOutput() << "|" << flush;
4427 }
4428 }
4429
4430 if (do_Hilbert_basis && Results[tn].get_collected_elements_size() > AdjustedReductionBound)
4431 skip_remaining = true;
4432 } catch (const std::exception&) {
4433 tmp_exception = std::current_exception();
4434 skip_remaining = true;
4435 #pragma omp flush(skip_remaining)
4436 }
4437 }
4438 Results[tn].transfer_candidates();
4439 } // end parallel
4440 if (!(tmp_exception == 0))
4441 std::rethrow_exception(tmp_exception);
4442
4443 if (verbose)
4444 verboseOutput() << endl;
4445
4446 update_reducers();
4447
4448 } while (skip_remaining);
4449
4450 } // do_evaluation
4451
4452 if (verbose) {
4453 size_t tot_nr_simpl;
4454 if(pulling_triangulation)
4455 tot_nr_simpl = TriangulationBuffer.size();
4456 else
4457 tot_nr_simpl = totalNrSimplices;
4458 verboseOutput() << tot_nr_simpl << " simplices";
4459 if (do_Hilbert_basis)
4460 verboseOutput() << ", " << CandidatesSize << " HB candidates";
4461 if (do_deg1_elements)
4462 verboseOutput() << ", " << CandidatesSize << " deg1 vectors";
4463 verboseOutput() << " accumulated." << endl;
4464 }
4465
4466 if(keep_triangulation_bitsets){
4467 for(auto& T: TriangulationBuffer)
4468 Triangulation_ind.push_back(make_pair(key_to_bitset(T.key, nr_gen),dynamic_bitset()));
4469 }
4470
4471 if (keep_triangulation) {
4472 Triangulation.splice(Triangulation.end(), TriangulationBuffer);
4473 }
4474 else {
4475 // #pragma omp critical(FREESIMPL)
4476 FreeSimpl.splice(FreeSimpl.begin(), TriangulationBuffer);
4477 }
4478 TriangulationBufferSize = 0;
4479
4480 if (verbose && use_bottom_points) {
4481 size_t lss = LargeSimplices.size();
4482 if (lss > 0)
4483 verboseOutput() << lss << " large simplices stored" << endl;
4484 }
4485
4486 for (size_t i = 0; i < Results.size(); ++i)
4487 Results[i].transfer_candidates(); // any remaining ones
4488
4489 update_reducers();
4490 }
4491
4492 #ifdef ENFNORMALIZ
4493 template <>
evaluate_triangulation()4494 void Full_Cone<renf_elem_class>::evaluate_triangulation() {
4495 assert(omp_get_level() == 0);
4496
4497 if (TriangulationBufferSize == 0)
4498 return;
4499
4500 if(pulling_triangulation)
4501 TriangulationBufferSize = TriangulationBuffer.size(); // the bookkeeping does not work in this case
4502
4503 totalNrSimplices += TriangulationBufferSize;
4504
4505 if (do_determinants) {
4506 bool dummy;
4507 bool skip_remaining = false;
4508 std::exception_ptr tmp_exception;
4509
4510 long nr_simplices_done = 0;
4511 #pragma omp parallel
4512 {
4513 Matrix<renf_elem_class> work;
4514 auto t = TriangulationBuffer.begin();
4515 size_t spos = 0;
4516 #pragma omp for
4517 for (size_t i = 0; i < TriangulationBufferSize; i++) {
4518 try {
4519 if (skip_remaining)
4520 continue;
4521
4522 for (; i > spos; ++spos, ++t)
4523 ;
4524 for (; i < spos; --spos, --t)
4525 ;
4526
4527 INTERRUPT_COMPUTATION_BY_EXCEPTION
4528
4529 work = Generators.submatrix(t->key);
4530 work.row_echelon_inner_elem(dummy);
4531 t->vol = 1;
4532 for (size_t i = 0; i < dim; ++i)
4533 t->vol *= work[i][i];
4534
4535 t->vol = Iabs(t->vol);
4536 t->mult = t->vol;
4537
4538 #pragma omp atomic
4539 TotDet++;
4540
4541 if (do_multiplicity) {
4542 renf_elem_class deg_prod = 1;
4543 for (size_t j = 0; j < dim; ++j) {
4544 deg_prod *= gen_degrees[t->key[j]];
4545 /* if(Truncation.size()>0){
4546 renf_elem_class test=v_scalar_product(Generators[t->key[j]],Truncation);
4547 assert(gen_degrees[t->key[j]]==test);
4548 }*/
4549 }
4550 t->mult /= deg_prod;
4551 }
4552
4553 #pragma omp atomic
4554 nr_simplices_done++;
4555
4556 if (verbose && nr_simplices_done % 10 == 0) {
4557 #pragma omp critical(PROGRESS)
4558 verboseOutput() << nr_simplices_done << " simplices done" << endl;
4559 }
4560
4561 } catch (const std::exception&) {
4562 tmp_exception = std::current_exception();
4563 skip_remaining = true;
4564 #pragma omp flush(skip_remaining)
4565 }
4566
4567 } // for
4568
4569 } // parallel
4570 if (!(tmp_exception == 0))
4571 std::rethrow_exception(tmp_exception);
4572
4573 auto t = TriangulationBuffer.begin();
4574 for (; t != TriangulationBuffer.end(); ++t) {
4575 INTERRUPT_COMPUTATION_BY_EXCEPTION
4576
4577 // t->vol=Generators.submatrix(t->key).vol();
4578 detSum += t->vol;
4579 if (do_multiplicity) {
4580 renf_multiplicity += t->mult;
4581 }
4582 }
4583 }
4584
4585 if (keep_triangulation) {
4586 Triangulation.splice(Triangulation.end(), TriangulationBuffer);
4587 }
4588 else {
4589 // #pragma omp critical(FREESIMPL)
4590 FreeSimpl.splice(FreeSimpl.begin(), TriangulationBuffer);
4591 }
4592 TriangulationBufferSize = 0;
4593 }
4594 #endif
4595
4596 //---------------------------------------------------------------------------
4597
4598 template <typename Integer>
evaluate_large_simplices()4599 void Full_Cone<Integer>::evaluate_large_simplices() {
4600 size_t lss = LargeSimplices.size();
4601 if (lss == 0)
4602 return;
4603
4604 assert(omp_get_level() == omp_start_level);
4605
4606 if (verbose) {
4607 verboseOutput() << "Evaluating " << lss << " large simplices" << endl;
4608 }
4609 size_t j;
4610 for (j = 0; j < lss; ++j) {
4611 INTERRUPT_COMPUTATION_BY_EXCEPTION
4612
4613 evaluate_large_simplex(j, lss);
4614 }
4615
4616 // decomposition might have created new simplices -- NO LONGER, now in Pyramids[0]
4617 // evaluate_triangulation();
4618
4619 // also new large simplices are possible
4620 /* if (!LargeSimplices.empty()) {
4621 use_bottom_points = false;
4622 lss += LargeSimplices.size();
4623 if (verbose) {
4624 verboseOutput() << "Continue evaluation of " << lss << " large simplices without new decompositions of simplicial
4625 cones." << endl;
4626 }
4627 for (; j < lss; ++j) {
4628
4629 INTERRUPT_COMPUTATION_BY_EXCEPTION
4630
4631 evaluate_large_simplex(j, lss);
4632 }
4633 }*/
4634 assert(LargeSimplices.empty());
4635
4636 for (size_t i = 0; i < Results.size(); ++i)
4637 Results[i].transfer_candidates(); // any remaining ones
4638
4639 update_reducers();
4640 }
4641
4642 //---------------------------------------------------------------------------
4643
4644 template <typename Integer>
evaluate_large_simplex(size_t j,size_t lss)4645 void Full_Cone<Integer>::evaluate_large_simplex(size_t j, size_t lss) {
4646 if (verbose) {
4647 verboseOutput() << "Large simplex " << j + 1 << " / " << lss << endl;
4648 }
4649
4650 if (do_deg1_elements && !do_h_vector && !do_Stanley_dec && !deg1_triangulation) {
4651 compute_deg1_elements_via_projection_simplicial(LargeSimplices.front().get_key());
4652 // one could think abot a condition in terms of the degrees of the generators -- deg1triangulation is a little coarse
4653 }
4654 else {
4655 LargeSimplices.front().Simplex_parallel_evaluation();
4656 if (do_Hilbert_basis && Results[0].get_collected_elements_size() > AdjustedReductionBound) {
4657 Results[0].transfer_candidates();
4658 update_reducers();
4659 }
4660 }
4661 LargeSimplices.pop_front();
4662 }
4663
4664 #ifdef ENFNORMALIZ
4665 template <>
evaluate_large_simplex(size_t j,size_t lss)4666 void Full_Cone<renf_elem_class>::evaluate_large_simplex(size_t j, size_t lss) {
4667 assert(false);
4668 }
4669 #endif
4670
4671 //---------------------------------------------------------------------------
4672
4673 template <typename Integer>
compute_deg1_elements_via_projection_simplicial(const vector<key_t> & key)4674 void Full_Cone<Integer>::compute_deg1_elements_via_projection_simplicial(const vector<key_t>& key) {
4675
4676 assert(!is_global_approximation); // allowed since we do not come here if deg1_triangulation
4677
4678 Matrix<Integer> Gens = Generators.submatrix(key);
4679 Sublattice_Representation<Integer> NewCoordinates = LLL_coordinates<Integer, Integer>(Gens);
4680 Matrix<Integer> Gred = NewCoordinates.to_sublattice(Gens);
4681 vector<Integer> GradT = NewCoordinates.to_sublattice_dual(Grading);
4682
4683 Cone<Integer> ProjCone(Type::cone, Gred, Type::grading, Matrix<Integer>(GradT));
4684 ConeProperties ForDeg1;
4685 ForDeg1.set(ConeProperty::Projection);
4686 ForDeg1.set(ConeProperty::NoLLL);
4687 if (using_GMP<Integer>())
4688 ForDeg1.set(ConeProperty::BigInt);
4689 ForDeg1.set(ConeProperty::Deg1Elements);
4690 ProjCone.compute(ForDeg1);
4691
4692 /*if(using_GMP<Integer>())
4693 ProjCone.compute(ConeProperty::Projection,ConeProperty::NoLLL,ConeProperty::BigInt,);
4694 else
4695 ProjCone.compute(ConeProperty::Projection,ConeProperty::NoLLL);*/
4696 Matrix<Integer> Deg1 = ProjCone.getDeg1ElementsMatrix();
4697 Deg1 = NewCoordinates.from_sublattice(Deg1); // back to the coordinates of the full cone
4698
4699 Matrix<Integer> Supp = ProjCone.getSupportHyperplanesMatrix();
4700 Supp = NewCoordinates.from_sublattice_dual(Supp);
4701
4702 /*for(size_t i=0;i<dim;++i)
4703 for(size_t j=0;j<dim;++j)
4704 assert(v_scalar_product(Supp[i],Gens[j])>=0); */
4705
4706 vector<bool> Excluded(dim, false); // we want to discard duplicates
4707 for (size_t i = 0; i < dim; ++i) { // first we find the excluded facets of our simplicial cone
4708 Integer test = v_scalar_product(Supp[i], Order_Vector);
4709 if (test > 0)
4710 continue;
4711 if (test < 0) {
4712 Excluded[i] = true;
4713 continue;
4714 }
4715 size_t j;
4716 for (j = 0; j < dim; ++j) {
4717 if (Supp[i][j] != 0)
4718 break;
4719 }
4720 if (Supp[i][j] < 0)
4721 Excluded[i] = true;
4722 }
4723
4724 for (const auto& E : Deg1.get_elements()) { // Now the duplicates are excluded
4725 size_t i;
4726 for (i = 0; i < dim; ++i)
4727 if (v_scalar_product(E, Supp[i]) == 0 && Excluded[i])
4728 break;
4729 if (i < dim) // E lies in an excluded facet
4730 continue;
4731
4732 // if(is_global_approximation && !subcone_contains(E)) // not contained in approximated cone
4733 // continue; // CANNOT HAPPEN SINCE ONLY USED IF !deg1_triangulation. See assert above
4734
4735 for (i = 0; i < dim; ++i) // exclude original generators -- will come in later
4736 if (E == Gens[i])
4737 break;
4738 if (i == dim) {
4739 Results[0].Deg1_Elements.push_back(E);
4740 Results[0].collected_elements_size++;
4741 }
4742 }
4743 Results[0].transfer_candidates();
4744 }
4745
4746 #ifdef ENFNORMALIZ
4747 template <>
compute_deg1_elements_via_projection_simplicial(const vector<key_t> & key)4748 void Full_Cone<renf_elem_class>::compute_deg1_elements_via_projection_simplicial(const vector<key_t>& key) {
4749 assert(false);
4750 }
4751 #endif
4752
4753 //---------------------------------------------------------------------------
4754
4755 /*
4756 template <typename Integer>
4757 void Full_Cone<Integer>::remove_duplicate_ori_gens_from_HB() {
4758 return; // TODO reactivate!
4759 Generators.max_rank_submatrix_lex().size()
4760 set<vector<Integer>> OriGens;
4761 for (auto c = OldCandidates.Candidates.begin(); c != OldCandidates.Candidates.end();) {
4762 if (!c->original_generator) {
4763 ++c;
4764 continue;
4765 }
4766 auto found = OriGens.find(c->cand);
4767 if (found != OriGens.end()) {
4768 c = OldCandidates.Candidates.erase(c);
4769 }
4770 else {
4771 if (c->original_generator)
4772 OriGens.insert(c->cand);
4773 ++c;
4774 }
4775 }
4776 }
4777 */
4778
4779 //---------------------------------------------------------------------------
4780
4781 template <typename Integer>
primal_algorithm()4782 void Full_Cone<Integer>::primal_algorithm() {
4783 if (!(do_deg1_elements || do_Hilbert_basis || do_h_vector || do_multiplicity || do_determinants || do_triangulation_size
4784 || do_signed_dec || do_pure_triang ) )
4785 return;
4786
4787 // primal_algorithm_initialize();
4788
4789 /***** Main Work is done in build_top_cone() *****/
4790 build_top_cone(); // evaluates if keep_triangulation==false
4791 /***** Main Work is done in build_top_cone() *****/
4792
4793 check_pointed();
4794 if (!pointed) {
4795 throw NonpointedException();
4796 }
4797
4798 primal_algorithm_finalize();
4799 primal_algorithm_set_computed();
4800 }
4801
4802 //---------------------------------------------------------------------------
4803
4804 template <typename Integer>
set_primal_algorithm_control_variables()4805 void Full_Cone<Integer>::set_primal_algorithm_control_variables() {
4806 do_triangulation = false;
4807 do_partial_triangulation = false;
4808 // stop_after_cone_dec = false;
4809 do_evaluation = false;
4810 // do_only_multiplicity = false;
4811 use_bottom_points = true;
4812 triangulation_is_nested = false;
4813 triangulation_is_partial = false;
4814
4815 if (do_multiplicity)
4816 do_determinants = true;
4817 if (do_determinants)
4818 do_triangulation = true;
4819 if(do_pure_triang)
4820 do_triangulation = true;
4821 if (do_triangulation_size)
4822 do_triangulation = true;
4823 if (do_h_vector)
4824 do_triangulation = true;
4825 if (do_deg1_elements)
4826 do_partial_triangulation = true;
4827 if (do_Hilbert_basis)
4828 do_partial_triangulation = true;
4829
4830 // activate
4831 do_only_multiplicity = do_determinants || do_multiplicity;
4832
4833 stop_after_cone_dec = true;
4834 if (do_cone_dec)
4835 do_only_multiplicity = false;
4836
4837 if (do_Stanley_dec || do_h_vector || do_deg1_elements || do_Hilbert_basis) {
4838 do_only_multiplicity = false;
4839 stop_after_cone_dec = false;
4840 do_evaluation = true;
4841 }
4842 if (do_determinants)
4843 do_evaluation = true;
4844
4845 if(pulling_triangulation){
4846 recursion_allowed = false;
4847 do_triangulation = true;
4848 do_only_multiplicity = false;
4849 // do_evaluation = false; // determinants will be computed separately
4850 }
4851
4852 // deactivate
4853 if (do_triangulation)
4854 do_partial_triangulation = false;
4855
4856 assert(! (do_evaluation && do_pure_triang));
4857
4858 // cout << "DOM " << do_only_multiplicity << " Tri " << do_triangulation << " Wit " << do_integrally_closed << endl;
4859 }
4860
4861 //---------------------------------------------------------------------------
4862
4863 template <typename Integer>
primal_algorithm_initialize()4864 void Full_Cone<Integer>::primal_algorithm_initialize() {
4865 set_primal_algorithm_control_variables();
4866
4867 if (verbose) {
4868 verboseOutput() << "Starting primal algorithm ";
4869 if (do_partial_triangulation)
4870 verboseOutput() << "with partial triangulation ";
4871 if (do_triangulation)
4872 verboseOutput() << "with full triangulation ";
4873 if (!do_triangulation && !do_partial_triangulation)
4874 verboseOutput() << "(only support hyperplanes) ";
4875 verboseOutput() << "..." << endl;
4876 }
4877
4878 prepare_inclusion_exclusion();
4879
4880 SimplexEval = vector<SimplexEvaluator<Integer>>(omp_get_max_threads(), SimplexEvaluator<Integer>(*this));
4881 for (size_t i = 0; i < SimplexEval.size(); ++i)
4882 SimplexEval[i].set_evaluator_tn(i);
4883 Results = vector<Collector<Integer>>(omp_get_max_threads(), Collector<Integer>(*this));
4884 Hilbert_Series.setVerbose(verbose);
4885 }
4886
4887 //---------------------------------------------------------------------------
4888
4889 template <typename Integer>
primal_algorithm_finalize()4890 void Full_Cone<Integer>::primal_algorithm_finalize() {
4891 if (isComputed(ConeProperty::Grading) && !deg1_generated) {
4892 deg1_triangulation = false;
4893 }
4894 if (keep_triangulation) {
4895 setComputed(ConeProperty::Triangulation);
4896 if(pulling_triangulation)
4897 setComputed(ConeProperty::PullingTriangulation);
4898 }
4899 if (do_cone_dec) {
4900 setComputed(ConeProperty::ConeDecomposition);
4901 }
4902
4903 evaluate_triangulation();
4904 assert(nrPyramids[0] == 0);
4905 evaluate_large_simplices(); // can produce level 0 pyramids
4906 use_bottom_points = false; // block new attempts for subdivision
4907 evaluate_stored_pyramids(0); // in case subdivision took place
4908 evaluate_triangulation();
4909 FreeSimpl.clear();
4910
4911 // collect accumulated data from the SimplexEvaluators
4912 for (int zi = 0; zi < omp_get_max_threads(); zi++) {
4913 detSum += Results[zi].getDetSum();
4914 multiplicity += Results[zi].getMultiplicitySum();
4915 if (do_h_vector) {
4916 Hilbert_Series += Results[zi].getHilbertSeriesSum();
4917 }
4918 }
4919 #ifdef NMZ_MIC_OFFLOAD
4920 // collect accumulated data from mics
4921 if (_Offload_get_device_number() < 0) // dynamic check for being on CPU (-1)
4922 {
4923 mic_offloader.finalize();
4924 }
4925 #endif // NMZ_MIC_OFFLOAD
4926 if (do_h_vector) {
4927 Hilbert_Series.collectData();
4928 }
4929
4930 if (verbose) {
4931 verboseOutput() << "Total number of pyramids = " << totalNrPyr << ", among them simplicial " << nrSimplicialPyr << endl;
4932 // cout << "Uni "<< Unimod << " Ht1NonUni " << Ht1NonUni << " NonDecided " << NonDecided << " TotNonDec " <<
4933 // NonDecidedHyp<< endl;
4934 if (do_only_multiplicity)
4935 verboseOutput() << "Determinants computed = " << TotDet << endl;
4936 /* if(NrCompVect>0)
4937 cout << "Vector comparisons " << NrCompVect << " Value comparisons " << NrCompVal
4938 << " Average " << NrCompVal/NrCompVect+1 << endl; */
4939 }
4940 }
4941
4942 //---------------------------------------------------------------------------
4943
4944 template <typename Integer>
make_module_gens()4945 void Full_Cone<Integer>::make_module_gens() {
4946 if (!inhomogeneous) {
4947 NewCandidates.extract(ModuleGeneratorsOverOriginalMonoid);
4948 vector<Integer> Zero(dim, 0);
4949 ModuleGeneratorsOverOriginalMonoid.push_front(Zero);
4950 // cout << "Mod " << endl;
4951 // Matrix<Integer>(ModuleGeneratorsOverOriginalMonoid).pretty_print(cout);
4952 // cout << "--------" << endl;
4953 setComputed(ConeProperty::ModuleGeneratorsOverOriginalMonoid, true);
4954 return;
4955 }
4956
4957 CandidateList<Integer> Level1OriGens;
4958 for (size_t i = 0; i < nr_gen; ++i) {
4959 if (gen_levels[i] == 1) {
4960 Level1OriGens.push_back(Candidate<Integer>(Generators[i], *this));
4961 }
4962 }
4963 CandidateList<Integer> Level1Generators = Level1OriGens;
4964 Candidate<Integer> new_cand(dim, Support_Hyperplanes.nr_of_rows());
4965 for (const auto& lnew : NewCandidates.Candidates) {
4966 INTERRUPT_COMPUTATION_BY_EXCEPTION
4967
4968 Integer level = v_scalar_product(lnew.cand, Truncation);
4969 if (level == 1) {
4970 new_cand = lnew;
4971 Level1Generators.reduce_by_and_insert(new_cand, OldCandidates);
4972 }
4973 else {
4974 for (const auto& l1 : Level1OriGens.Candidates) {
4975 new_cand = sum(l1, lnew);
4976 Level1Generators.reduce_by_and_insert(new_cand, OldCandidates);
4977 }
4978 }
4979 }
4980 Level1Generators.extract(ModuleGeneratorsOverOriginalMonoid);
4981 ModuleGeneratorsOverOriginalMonoid.sort();
4982 ModuleGeneratorsOverOriginalMonoid.unique();
4983 setComputed(ConeProperty::ModuleGeneratorsOverOriginalMonoid, true);
4984
4985 for (size_t i = 0; i < nr_gen; i++) { // the level 1 input generators have not yet ben inserted into OldCandidates
4986 if (gen_levels[i] == 1) { // but they are needed for the truncated Hilbert basis com?putation
4987 NewCandidates.Candidates.push_back(Candidate<Integer>(Generators[i], *this));
4988 NewCandidates.Candidates.back().original_generator = true;
4989 }
4990 }
4991 }
4992
4993 //---------------------------------------------------------------------------
4994
4995 template <typename Integer>
make_module_gens_and_extract_HB()4996 void Full_Cone<Integer>::make_module_gens_and_extract_HB() {
4997 make_module_gens();
4998
4999 NewCandidates.divide_sortdeg_by2(); // was previously multplied by 2
5000 NewCandidates.sort_by_deg();
5001
5002 OldCandidates.merge(NewCandidates);
5003 OldCandidates.auto_reduce();
5004 }
5005
5006 //---------------------------------------------------------------------------
5007
5008 template <typename Integer>
finish_Hilbert_series()5009 void Full_Cone<Integer>::finish_Hilbert_series() {
5010 if (do_h_vector) {
5011 Hilbert_Series.setShift(convertToLong(shift));
5012 Hilbert_Series.adjustShift();
5013 // now the shift in the HilbertSeries may change and we would have to adjust
5014 // the shift, the grading and more in the Full_Cone to continue to add data!
5015 // COMPUTE HSOP here
5016 if (do_hsop) {
5017 compute_hsop();
5018 setComputed(ConeProperty::HSOP);
5019 }
5020 Hilbert_Series.simplify();
5021 setComputed(ConeProperty::HilbertSeries);
5022 }
5023 }
5024
5025 template <>
finish_Hilbert_series()5026 void Full_Cone<renf_elem_class>::finish_Hilbert_series() {
5027 assert(false);
5028 }
5029
5030 template <typename Integer>
primal_algorithm_set_computed()5031 void Full_Cone<Integer>::primal_algorithm_set_computed() {
5032 extreme_rays_and_deg1_check();
5033 if (!pointed) {
5034 throw NonpointedException();
5035 }
5036
5037 if (do_triangulation || do_partial_triangulation) {
5038 setComputed(ConeProperty::TriangulationSize, true);
5039 if (do_evaluation) {
5040 setComputed(ConeProperty::TriangulationDetSum);
5041 }
5042 }
5043 if ((do_triangulation && do_evaluation && isComputed(ConeProperty::Grading)) || (do_multiplicity && using_renf<Integer>()))
5044 setComputed(ConeProperty::Multiplicity);
5045
5046 INTERRUPT_COMPUTATION_BY_EXCEPTION
5047
5048 if (do_Hilbert_basis) {
5049 if (hilbert_basis_rec_cone_known) {
5050 // OldCandidates.Candidates.clear();
5051 OldCandidates.merge(HBRC);
5052 OldCandidates.merge(ModuleGensDepot);
5053 }
5054 if (do_module_gens_intcl) {
5055 make_module_gens_and_extract_HB();
5056 }
5057 OldCandidates.sort_by_val();
5058 OldCandidates.extract(Hilbert_Basis);
5059 OldCandidates.Candidates.clear();
5060 Hilbert_Basis.unique();
5061 setComputed(ConeProperty::HilbertBasis, true);
5062 }
5063
5064 if (isComputed(ConeProperty::Grading) && isComputed(ConeProperty::HilbertBasis)) {
5065 select_deg1_elements();
5066 check_deg1_hilbert_basis();
5067 }
5068
5069 INTERRUPT_COMPUTATION_BY_EXCEPTION
5070
5071 if (do_deg1_elements) {
5072 for(size_t i=0;i<nr_gen;i++)
5073 if(v_scalar_product(Grading,Generators[i])==1 && (!is_global_approximation
5074 || subcone_contains(Generators[i])))
5075 Deg1_Elements.push_front(Generators[i]);
5076 setComputed(ConeProperty::Deg1Elements, true);
5077 Deg1_Elements.sort();
5078 Deg1_Elements.unique();
5079 }
5080
5081 INTERRUPT_COMPUTATION_BY_EXCEPTION
5082
5083 if (do_h_vector)
5084 finish_Hilbert_series();
5085
5086 if (do_Stanley_dec) {
5087 setComputed(ConeProperty::StanleyDec);
5088 }
5089
5090 // If the grading has gcd > 1 on the recession monoid,
5091 // we must multiply the multiplicity by it.
5092 // Without this correction, the multiplicity (relative to deg/g)
5093 // is divided by g^r, but it must be g^{r-1}.
5094 // We determine g and multiply by it.
5095 //
5096 // The reason behind this correction is that the determinants
5097 // are computed with respect to a basis in which the
5098 // basic simplex has volume 1/g instead of 1.
5099 // The correction above takes care of this "mistake"
5100 // that we are forced to make in order to keep data integral.
5101
5102 if (isComputed(ConeProperty::Multiplicity)) {
5103 Integer corr_factor;
5104 if (!inhomogeneous)
5105 corr_factor = v_gcd(Grading);
5106 if (inhomogeneous && level0_dim == 0)
5107 corr_factor = 1;
5108 if (inhomogeneous && level0_dim > 0) {
5109 Matrix<Integer> Level0Space = ProjToLevel0Quot.kernel();
5110 corr_factor = 0;
5111 for (size_t i = 0; i < Level0Space.nr_of_rows(); ++i)
5112 corr_factor = libnormaliz::gcd(corr_factor, v_scalar_product(Grading, Level0Space[i]));
5113 }
5114 multiplicity *= convertTo<mpz_class>(corr_factor);
5115 }
5116 }
5117
5118 //---------------------------------------------------------------------------
5119
5120 template <typename Integer>
set_degrees()5121 void Full_Cone<Integer>::set_degrees() {
5122 // Generators.pretty_print(cout);
5123 // cout << "Grading " << Grading;
5124 if (gen_degrees.size() != nr_gen && isComputed(ConeProperty::Grading)) // now we set the degrees
5125 {
5126 gen_degrees.resize(nr_gen);
5127 if (do_h_vector || (!using_GMP<Integer>() && !using_renf<Integer>()))
5128 gen_degrees_long.resize(nr_gen);
5129 gen_degrees = Generators.MxV(Grading);
5130 for (size_t i = 0; i < nr_gen; i++) {
5131 if (gen_degrees[i] <= 0) {
5132 throw BadInputException("Grading gives non-positive value " + toString(gen_degrees[i]) + " for generator " +
5133 toString(i + 1) + ".");
5134 }
5135 if (do_h_vector || (!using_GMP<Integer>() && !using_renf<Integer>()))
5136 convert(gen_degrees_long[i], gen_degrees[i]);
5137 }
5138 }
5139 }
5140
5141 #ifdef ENFNORMALIZ
5142 template <>
set_degrees()5143 void Full_Cone<renf_elem_class>::set_degrees() {
5144 if (!isComputed(ConeProperty::Grading) && !inhomogeneous)
5145 return;
5146
5147 vector<renf_elem_class> GradHelp = Grading;
5148 if (inhomogeneous)
5149 GradHelp = Truncation;
5150
5151 gen_degrees = Generators.MxV(GradHelp);
5152 for (size_t i = 0; i < Generators.nr_of_rows(); ++i)
5153 if (gen_degrees[i] <= 0 && (do_multiplicity || do_automorphisms))
5154 throw BadInputException("Volume or automorphism group not computable for unbounded nalgebraic polyhedra");
5155 }
5156 #endif
5157
5158 //---------------------------------------------------------------------------
5159 // Normaliz modes (public)
5160 //---------------------------------------------------------------------------
5161
5162 // check the do_* bools, they must be set in advance
5163 // this method (de)activates them according to dependencies between them
5164 template <typename Integer>
set_preconditions()5165 void Full_Cone<Integer>::set_preconditions() {
5166 do_extreme_rays = true; // we always want to do this if compute() is called
5167
5168 /* if (do_default_mode && with_default) {
5169 do_Hilbert_basis = true;
5170 do_h_vector = true;
5171 if(!inhomogeneous)
5172 do_class_group=true;
5173 }
5174 */
5175
5176 if (do_integrally_closed) {
5177 if (do_Hilbert_basis) {
5178 do_integrally_closed = false; // don't interrupt the computation
5179 }
5180 else {
5181 do_Hilbert_basis = true;
5182 }
5183 }
5184
5185 // activate implications
5186 if (do_module_gens_intcl)
5187 do_Hilbert_basis = true;
5188 if (do_module_gens_intcl)
5189 use_bottom_points = false; // extra bottom points change the originalmonoid
5190 if (do_Stanley_dec)
5191 keep_triangulation = true;
5192 if (do_pure_triang)
5193 keep_triangulation = true;
5194 if(pulling_triangulation){
5195 keep_triangulation = true;
5196 keep_order = true;
5197 }
5198 if (do_cone_dec)
5199 keep_triangulation = true;
5200 if (keep_triangulation)
5201 do_determinants = true;
5202
5203 do_signed_dec = do_multiplicity_by_signed_dec || do_integral_by_signed_dec || do_virtual_multiplicity_by_signed_dec;
5204
5205 if(include_dualization)
5206 assert(do_signed_dec);
5207 if(do_signed_dec){
5208 keep_triangulation_bitsets = true;
5209 keep_order=true; // ???
5210 do_pure_triang = true;
5211 if(!include_dualization){
5212 do_all_hyperplanes = false;
5213 do_extreme_rays = false;
5214 believe_pointed = true;
5215 }
5216 }
5217 if(keep_order)
5218 suppress_bottom_dec = true;
5219
5220 // if (do_multiplicity) do_determinants = true; // removed because of automorphisms
5221 if ((do_multiplicity || do_h_vector) && inhomogeneous)
5222 do_module_rank = true;
5223 if (do_Hilbert_basis)
5224 do_deg1_elements = false; // after the Hilbert basis computation, deg 1 elements will be extracted
5225 if(keep_convex_hull_data)
5226 suppress_bottom_dec = true;
5227
5228 // to exclude descent to facets in the exploitation of automorphism groups: we must use the primal algorithm directly
5229 no_descent_to_facets = do_h_vector || do_module_gens_intcl || keep_triangulation
5230 || do_triangulation_size || do_Stanley_dec || do_cone_dec || do_determinants || do_excluded_faces ||
5231 do_bottom_dec;
5232
5233 do_only_supp_hyps_and_aux = !do_pure_triang &&
5234 !no_descent_to_facets && !do_multiplicity && !do_deg1_elements && !do_Hilbert_basis && !do_signed_dec;
5235 }
5236
5237 // We set the do* variables to false if the corresponding task has been done
5238 template <typename Integer>
deactivate_completed_tasks()5239 void Full_Cone<Integer>::deactivate_completed_tasks() {
5240 if (isComputed(ConeProperty::IsPointed))
5241 do_pointed = false;
5242 if (isComputed(ConeProperty::ExtremeRays))
5243 do_extreme_rays = false;
5244 if (isComputed(ConeProperty::HilbertBasis)) {
5245 do_Hilbert_basis = false;
5246 do_integrally_closed = false;
5247 }
5248 if (isComputed(ConeProperty::Deg1Elements))
5249 do_deg1_elements = false;
5250 if (isComputed(ConeProperty::ModuleGeneratorsOverOriginalMonoid))
5251 do_module_gens_intcl = false;
5252
5253 if (isComputed(ConeProperty::HilbertSeries))
5254 do_h_vector = false;
5255 if (isComputed(ConeProperty::Multiplicity))
5256 do_multiplicity = false;
5257
5258 if (isComputed(ConeProperty::StanleyDec))
5259 do_Stanley_dec = false;
5260 if (isComputed(ConeProperty::ConeDecomposition))
5261 do_cone_dec = false;
5262 if (isComputed(ConeProperty::Triangulation))
5263 keep_triangulation = false;
5264 if (isComputed(ConeProperty::TriangulationDetSum))
5265 do_determinants = false;
5266
5267 if (isComputed(ConeProperty::ModuleRank))
5268 do_module_rank = false;
5269
5270 if (isComputed(ConeProperty::ClassGroup))
5271 do_class_group = false;
5272 }
5273
5274 //---------------------------------------------------------------------------
5275
5276 /* deactivated at present
5277
5278 // do computations using automorphisms
5279 template <typename Integer>
5280 void Full_Cone<Integer>::compute_by_automorphisms() {
5281 if ((!exploit_automs_mult && !exploit_automs_vectors) || no_descent_to_facets)
5282 return;
5283
5284 if (descent_level == 0) {
5285 if (do_Hilbert_basis) {
5286 for (size_t i = 0; i < nr_gen; ++i)
5287 Generator_Set.insert(Generators[i]);
5288 }
5289
5290 if (autom_codim_vectors < 0) // set default values if not set by Cone
5291 autom_codim_vectors = 1;
5292 if (autom_codim_mult < 0)
5293 autom_codim_mult = min((int)dim / 4, 6);
5294 }
5295
5296 if (exploit_automs_mult && do_multiplicity) {
5297 if (descent_level < autom_codim_mult && nr_gen >= dim + 4) { // otherwise direct computation
5298 if (inhomogeneous)
5299 compute_multiplicity_via_recession_cone();
5300 else
5301 compute_multiplicity_via_automs();
5302 }
5303 setComputed(ConeProperty::ExploitIsosMult);
5304 }
5305 deactivate_completed_tasks();
5306
5307 if (exploit_automs_vectors && do_Hilbert_basis) {
5308 if (descent_level < autom_codim_vectors && nr_gen >= dim + 4) { // otherwise direct computation
5309 compute_HB_via_automs();
5310 }
5311 setComputed(ConeProperty::ExploitAutomsVectors);
5312 }
5313 deactivate_completed_tasks();
5314
5315 if (exploit_automs_vectors && do_deg1_elements) {
5316 if (descent_level < God_Father->autom_codim_mult && nr_gen >= dim + 4) { // otherwise direct computation
5317 compute_Deg1_via_automs();
5318 }
5319 setComputed(ConeProperty::ExploitAutomsVectors);
5320 }
5321 deactivate_completed_tasks();
5322 }
5323
5324 size_t nr_revlex_simpl = 0;
5325
5326 */
5327
5328 /* deactivated at present
5329
5330 //---------------------------------------------------------------------------
5331 template <typename Integer>
5332 void Full_Cone<Integer>::recursive_revlex_triangulation(
5333 vector<key_t> simplex_so_far,
5334 const vector<key_t>& face_key,
5335 const vector<typename list<FACETDATA<Integer>>::const_iterator>& mother_facets,
5336 size_t dim) {
5337 INTERRUPT_COMPUTATION_BY_EXCEPTION
5338
5339 // cout << "FACE KEY "<< face_key;
5340 // cout << "SIMPLex " << simplex_so_far;
5341
5342 // handle simplex case first since no further descent is necessary
5343
5344 if (face_key.size() == dim) {
5345 simplex_so_far.insert(simplex_so_far.end(), face_key.begin(), face_key.end());
5346 nr_revlex_simpl++;
5347 if (nr_revlex_simpl % 10000 == 0) {
5348 cout << "NR REVLEX SIMPL " << nr_revlex_simpl << endl;
5349 }
5350 return;
5351 }
5352
5353 // We first find the support hyperplanes of our top cone that cut out the
5354 // facets of our face
5355
5356 vector<vector<bool>> facet_candidates;
5357
5358 vector<typename list<FACETDATA<Integer>>::const_iterator> candidates_iterators;
5359
5360 for (size_t i = 0; i < mother_facets.size(); ++i) {
5361 auto F = mother_facets[i];
5362
5363 vector<bool> intersection(nr_gen);
5364 size_t nr_intersection = 0;
5365 for (unsigned int j : face_key) {
5366 if (F->GenInHyp[j]) {
5367 intersection[j] = true;
5368 nr_intersection++;
5369 }
5370 }
5371 // cout << "NR " << nr_intersection << endl;
5372 if (nr_intersection < dim - 1 || nr_intersection == face_key.size()) // too small or everything
5373 continue;
5374 facet_candidates.push_back(intersection);
5375 candidates_iterators.push_back(F);
5376 }
5377
5378 vector<bool> the_facets(facet_candidates.size(), true);
5379 maximal_subsets(facet_candidates, the_facets);
5380
5381 vector<typename list<FACETDATA<Integer>>::const_iterator> facets_of_this_face;
5382 for (size_t i = 0; i < the_facets.size(); ++i)
5383 if (the_facets[i])
5384 facets_of_this_face.push_back(candidates_iterators[i]);
5385
5386 // now we have the facets of our face via support hyperplanes of the top cone
5387
5388 // Next we go over those facets that are opposite to next_vert
5389
5390 key_t next_vert = face_key[0];
5391 simplex_so_far.push_back(next_vert);
5392
5393 for (size_t i = 0; i < facets_of_this_face.size(); ++i) {
5394 auto F = facets_of_this_face[i];
5395
5396 if (F->GenInHyp[next_vert]) // want only those opposite to next_vert
5397 continue;
5398 vector<key_t> intersection;
5399 for (unsigned int j : face_key) {
5400 if (F->GenInHyp[j])
5401 intersection.push_back(j);
5402 }
5403
5404 recursive_revlex_triangulation(simplex_so_far, intersection, facets_of_this_face, dim - 1);
5405 }
5406 }
5407
5408 //---------------------------------------------------------------------------
5409 template <typename Integer>
5410 void Full_Cone<Integer>::make_facets() {
5411 if (!isComputed(ConeProperty::SupportHyperplanes))
5412 support_hyperplanes();
5413 assert(Facets.empty());
5414 for (size_t i = 0; i < Support_Hyperplanes.nr_of_rows(); ++i) {
5415 FACETDATA<Integer> NewFacet;
5416 NewFacet.Hyp.resize(dim);
5417 NewFacet.GenInHyp.resize(nr_gen);
5418 for (size_t j = 0; j < nr_gen; ++j)
5419 if (v_scalar_product(Support_Hyperplanes[i], Generators[j]) == 0)
5420 NewFacet.GenInHyp[j] = true;
5421 NewFacet.Hyp = Support_Hyperplanes[i];
5422 Facets.push_back(NewFacet);
5423 }
5424 }
5425
5426 //---------------------------------------------------------------------------
5427 template <typename Integer>
5428 void Full_Cone<Integer>::revlex_triangulation() {
5429 make_facets();
5430 compute_extreme_rays(true);
5431 vector<key_t> simplex_so_far;
5432 simplex_so_far.reserve(dim);
5433 vector<key_t> Extreme_Rays_Key;
5434 for (size_t i = 0; i < nr_gen; ++i)
5435 if (Extreme_Rays_Ind[i])
5436 Extreme_Rays_Key.push_back(i);
5437
5438 vector<typename list<FACETDATA<Integer>>::const_iterator> mother_facets;
5439
5440 typename list<FACETDATA<Integer>>::const_iterator F;
5441 for (F = Facets.begin(); F != Facets.end(); ++F)
5442 mother_facets.push_back(F);
5443
5444 recursive_revlex_triangulation(simplex_so_far, Extreme_Rays_Key, mother_facets, dim);
5445
5446 cout << "FINAL NR REVLEX SIMPL " << nr_revlex_simpl << endl;
5447
5448 exit(0);
5449 }
5450 */
5451
5452 //---------------------------------------------------------------------------
5453 // general purpose compute method
5454 // do_* bools must be set in advance, this method does sanity checks for it
5455 // if no bool is set it does support hyperplanes and extreme rays
5456 template <typename Integer>
compute()5457 void Full_Cone<Integer>::compute() {
5458
5459 InputGenerators = Generators; // purified input -- in case we get an exception
5460
5461 // Safeguard against the removal of input generators despite that extreme rays
5462 // had been computed in the cone.
5463 if(Extreme_Rays_Ind.size()!=0 && Extreme_Rays_Ind.size() != Generators.nr_of_rows()){
5464 is_Computed.reset(ConeProperty::ExtremeRays);
5465 Extreme_Rays_Ind.resize(0);
5466 }
5467
5468 omp_start_level = omp_get_level();
5469
5470 /*cout << "==============" << endl;
5471 Generators.pretty_print(cout);
5472 cout << "==============" << endl;*/
5473
5474 if (dim == 0) {
5475 set_zero_cone();
5476 deactivate_completed_tasks();
5477 prepare_inclusion_exclusion();
5478 return;
5479 }
5480
5481 if(using_renf<Integer>()){
5482 assert(Truncation.size() == 0 || Grading.size() == 0);
5483 Norm = Truncation;
5484 if (Grading.size() > 0)
5485 Norm = Grading;
5486 }
5487
5488 set_preconditions();
5489 start_message();
5490
5491 if(do_signed_dec){
5492 primal_algorithm();
5493 compute_multiplicity_or_integral_by_signed_dec();
5494 return;
5495 }
5496
5497 if (!do_Hilbert_basis && !do_h_vector && !do_multiplicity && !do_deg1_elements && !do_Stanley_dec && !keep_triangulation &&
5498 !do_determinants)
5499 assert(Generators.max_rank_submatrix_lex().size() == dim);
5500
5501 if(do_integrally_closed){
5502 for (size_t i = 0; i < nr_gen; ++i)
5503 Generator_Set.insert(Generators[i]);
5504 }
5505
5506 minimize_support_hyperplanes(); // if they are given
5507 if (inhomogeneous)
5508 set_levels();
5509
5510 check_given_grading();
5511 // look for a grading if it is needed
5512 if(!using_renf<Integer>())
5513 find_grading();
5514
5515 if (isComputed(ConeProperty::IsPointed) && !pointed) {
5516 end_message();
5517 return;
5518 }
5519 if (!isComputed(ConeProperty::Grading) && !using_renf<Integer>())
5520 disable_grading_dep_comp();
5521
5522 // revlex_triangulation(); was here for test
5523
5524 if (do_only_supp_hyps_and_aux || (Grading.size() > 0 && !isComputed(ConeProperty::Grading))) {
5525 // in the last case there are only two possibilities:
5526 // either nonpointed or bad grading
5527
5528 // primal_algorithm_initialize();
5529 support_hyperplanes();
5530 InputGenerators = Generators; // purified input
5531 if(check_semiopen_empty)
5532 prepare_inclusion_exclusion();
5533 if(!using_renf<Integer>())
5534 compute_class_group();
5535 compute_automorphisms();
5536 deactivate_completed_tasks();
5537 end_message();
5538 return;
5539 }
5540
5541 if (isComputed(ConeProperty::IsPointed) && !pointed) {
5542 end_message();
5543 return;
5544 }
5545
5546 set_degrees();
5547 sort_gens_by_degree(true);
5548 InputGenerators = Generators; // purified input
5549
5550 bool polyhedron_is_polytope = inhomogeneous;
5551 if (inhomogeneous) {
5552 find_level0_dim();
5553 for (size_t i = 0; i < nr_gen; ++i)
5554 if (gen_levels[i] == 0) {
5555 polyhedron_is_polytope = false;
5556 break;
5557 }
5558 }
5559 if (polyhedron_is_polytope && (do_Hilbert_basis || do_h_vector)) { // inthis situation we must just find the
5560 convert_polyhedron_to_polytope(); // degree 1 points
5561 deactivate_completed_tasks();
5562 }
5563
5564 // compute_by_automorphisms();
5565 deactivate_completed_tasks();
5566
5567 primal_algorithm(); // here plays the music
5568 deactivate_completed_tasks();
5569
5570 if (!using_renf<Integer>() && inhomogeneous && descent_level == 0) {
5571 find_module_rank();
5572 }
5573
5574 if(!using_renf<Integer>())
5575 compute_class_group();
5576 compute_automorphisms();
5577 deactivate_completed_tasks();
5578
5579 end_message();
5580 }
5581
5582 // compute the degree vector of a hsop
5583 template <typename Integer>
degrees_hsop(const vector<Integer> gen_degrees,const vector<size_t> heights)5584 vector<Integer> degrees_hsop(const vector<Integer> gen_degrees, const vector<size_t> heights) {
5585 vector<Integer> hsop(heights.back());
5586 hsop[0] = gen_degrees[0];
5587 size_t k = 1;
5588 while (k < heights.size() && heights[k] > heights[k - 1]) {
5589 hsop[k] = gen_degrees[k];
5590 k++;
5591 }
5592 size_t j = k;
5593 for (size_t i = k; i < heights.size(); i++) {
5594 if (heights[i] > heights[i - 1]) {
5595 hsop[j] = v_lcm_to(gen_degrees, k, i);
5596 j++;
5597 }
5598 }
5599 return hsop;
5600 }
5601
5602 /*
5603 //---------------------------------------------------------------------------
5604 template<typename Integer>
5605 Matrix<Integer> Full_Cone<Integer>::copy_basic_data_from(const Full_Cone<Integer>& C){
5606 if(C.isComputed(ConeProperty::SupportHyperplanes)){
5607 Support_Hyperplanes=C.Support_Hyperplanes;
5608 nrSupport_Hyperplanes=C.nrSupport_Hyperplanes;
5609 setComputed(ConeProperty::SupportHyperplanes);
5610 }
5611 if(C.isComputed(ConeProperty::ExtremeRays)){
5612 Extreme_Rays_Ind=C.Extreme_Rays_Ind;
5613 setComputed(ConeProperty::ExtremeRays);
5614 }
5615 if(C.isComputed(ConeProperty::Automorphisms)){
5616 Automs=C.Automs;
5617 setComputed(ConeProperty::Automorphisms);
5618 }
5619 exploit_automorphisms=C.exploit_automorphisms;
5620 keep_order=true;
5621 verbose=C.verbose;
5622 descent_level=C.descent_level;
5623
5624
5625 Facet_2.Grading=Facet_Sub.to_sublattice_dual_no_div(Grading);
5626 Facet_2.setComputed(ConeProperty::Grading);
5627 Facet_2.Mother=&(*this);
5628 Facet_2.God_Father=God_Father;
5629 Facet_2.do_multiplicity=true;
5630
5631 }
5632 */
5633
5634 /* deactivated at present
5635 //---------------------------------------------------------------------------
5636 template <typename Integer>
5637 Matrix<Integer> Full_Cone<Integer>::push_supphyps_to_cone_over_facet(const vector<Integer>& fixed_point, const key_t facet_nr) {
5638 Matrix<Integer> SuppHyps(0, dim);
5639 vector<Integer> Facet = Support_Hyperplanes[facet_nr];
5640 SuppHyps.append(Facet);
5641 Integer h = v_scalar_product(fixed_point, Facet);
5642 vector<Integer> NewFacet(dim);
5643 for (key_t i = 0; i < nrSupport_Hyperplanes; ++i) {
5644 if (i == facet_nr)
5645 continue;
5646 Integer hN = v_scalar_product(fixed_point, Support_Hyperplanes[i]);
5647 NewFacet = FM_comb(Facet, h, Support_Hyperplanes[i], hN);
5648 SuppHyps.append(NewFacet);
5649 }
5650 return SuppHyps;
5651 }
5652
5653 //---------------------------------------------------------------------------
5654
5655 template <typename Integer>
5656 void Full_Cone<Integer>::copy_autom_params(const Full_Cone<Integer>& C) {
5657 exploit_automs_mult = C.exploit_automs_mult;
5658 exploit_automs_vectors = C.exploit_automs_vectors;
5659 quality_of_automorphisms = C.quality_of_automorphisms;
5660 do_automorphisms = C.do_automorphisms;
5661 keep_order = true;
5662 }
5663 //---------------------------------------------------------------------------
5664 // We want to replace the fixed point by a generator of the cone that has smaller height
5665 // over the base facet of the pyramid such that the fixed point is contained in the_facets
5666 // pyramid with base the facet and apex the generator
5667
5668 template<typename Integer>
5669 vector<Integer> Full_Cone<Integer>::replace_fixed_point_by_generator(const vector<Integer>& fixed_point,
5670 const key_t facet_nr, const vector<Integer>& help_grading){
5671
5672 Integer height_fixed_pt=v_scalar_product(Support_Hyperplanes[facet_nr],fixed_point);
5673 if(height_fixed_pt<=1)
5674 return fixed_point;
5675
5676 Integer deg_fp=v_scalar_product(fixed_point,help_grading);
5677 Integer height_fp=v_scalar_product(fixed_point,Support_Hyperplanes[facet_nr]);
5678
5679 bool first=true;
5680 Integer min_height;
5681 vector<Integer> min_ht_gen;
5682
5683 for(size_t i=0;i<nr_gen;++i){
5684 Integer height_gen=v_scalar_product(Support_Hyperplanes[facet_nr],Generators[i]);
5685 Integer deg_gen=v_scalar_product(Generators[i],help_grading);
5686 if(deg_fp*height_gen<=deg_gen*height_fp)
5687 continue;
5688 vector<Integer> test=FM_comb(fixed_point,height_fp,Generators[i],height_gen,false);
5689 bool in_cone=true;
5690 for(size_t j=0;j<Support_Hyperplanes.nr_of_rows();++j){
5691 if(v_scalar_product(test,Support_Hyperplanes[j])<0){
5692 in_cone=false;
5693 break;
5694 }
5695 }
5696 if(!in_cone)
5697 continue;
5698 if(first || height_gen<min_height){
5699 first=false;
5700 min_ht_gen=Generators[i];
5701 min_height=height_gen;
5702 }
5703 }
5704
5705 if(!first && min_height<height_fp)
5706 return min_ht_gen;
5707 else{
5708 cout << "No generator found" << endl;
5709 return fixed_point;
5710 }
5711 } // inner C comment ends here
5712 //---------------------------------------------------------------------------
5713 // version without iso classes
5714 template <typename Integer>
5715 void Full_Cone<Integer>::get_cone_over_facet_vectors(const vector<Integer>& fixed_point,
5716 const vector<key_t>& facet_key,
5717 const key_t facet_nr,
5718 list<vector<Integer>>& Facet_vectors) {
5719 vector<Integer> help_grading = compute_degree_function();
5720
5721 Matrix<Integer> Facet_Gens(0, dim);
5722 // vector<Integer> selected_gen=replace_fixed_point_by_generator(fixed_point,facet_nr,help_grading);
5723 // cpuld be the fixed point
5724 Facet_Gens.append(fixed_point);
5725 Facet_Gens.append(Generators.submatrix(facet_key));
5726
5727 if (verbose) {
5728 verboseOutput() << "Finding Hilbert basis/deg 1 elements for cone over codim " << descent_level + 1 << " face" << endl;
5729 verboseOutput() << "Height of pyramid apex over face " << v_scalar_product(fixed_point, Support_Hyperplanes[facet_nr])
5730 << endl;
5731 }
5732
5733 Full_Cone ConeOverFacet(Facet_Gens);
5734 ConeOverFacet.verbose = verbose;
5735
5736 if (isComputed(ConeProperty::Grading)) {
5737 ConeOverFacet.Grading = Grading;
5738 ConeOverFacet.setComputed(ConeProperty::Grading);
5739 }
5740 ConeOverFacet.descent_level = descent_level + 1;
5741 ConeOverFacet.Mother = &(*this);
5742 ConeOverFacet.God_Father = God_Father;
5743 if (ConeOverFacet.descent_level < God_Father->autom_codim_vectors) { // otherwise dirct computation of HB
5744 ConeOverFacet.copy_autom_params(*this);
5745 ConeOverFacet.Embedding = Embedding;
5746 }
5747 ConeOverFacet.Support_Hyperplanes = push_supphyps_to_cone_over_facet(fixed_point, facet_nr);
5748 ConeOverFacet.do_Hilbert_basis = do_Hilbert_basis;
5749 ConeOverFacet.do_deg1_elements = do_deg1_elements;
5750 ConeOverFacet.inhomogeneous = inhomogeneous;
5751 if (inhomogeneous) {
5752 ConeOverFacet.Truncation = Truncation;
5753 }
5754 ConeOverFacet.autom_codim_vectors = autom_codim_vectors;
5755 ConeOverFacet.compute();
5756 Facet_vectors.clear();
5757 if (do_Hilbert_basis)
5758 Facet_vectors.splice(Facet_vectors.begin(), ConeOverFacet.Hilbert_Basis);
5759 else
5760 Facet_vectors.splice(Facet_vectors.begin(), ConeOverFacet.Deg1_Elements);
5761 }
5762
5763 //---------------------------------------------------------------------------
5764 template <typename Integer>
5765 void Full_Cone<Integer>::compute_Deg1_via_automs() {
5766 compute_automorphisms(descent_level);
5767
5768 if (!do_deg1_elements || isComputed(ConeProperty::Deg1Elements) || !isComputed(ConeProperty::Automorphisms) ||
5769 Automs.getOrder() == 1)
5770 return;
5771
5772 list<vector<Integer>> union_of_facets; // collects all candidates from the orbits of the HBs of the facets
5773 vector<Integer> fixed_point = get_fixed_point(descent_level);
5774
5775 if (verbose) {
5776 verboseOutput() << "Computing deg1 elements via automorphisms in codim " << descent_level << endl;
5777 verboseOutput() << "Fixed point " << fixed_point;
5778 }
5779
5780 vector<vector<key_t>> facet_keys = get_facet_keys_for_orbits(fixed_point, false);
5781
5782 for (auto& facet_key : facet_keys) {
5783 list<vector<Integer>> facet_Deg1;
5784 key_t facet_nr = facet_key.back();
5785 facet_key.pop_back();
5786 get_cone_over_facet_vectors(fixed_point, facet_key, facet_nr, facet_Deg1);
5787
5788 list<vector<Integer>> union_of_orbits; // we must spread the deg 1 elements over their orbit
5789 for (const auto& c : facet_Deg1) {
5790 list<vector<Integer>> orbit_of_deg1 = Automs.orbit_primal(c);
5791 union_of_orbits.splice(union_of_orbits.end(), orbit_of_deg1);
5792 }
5793 union_of_orbits.sort();
5794 union_of_facets.merge(union_of_orbits);
5795 }
5796 union_of_facets.unique(); // necesary since dupocates cannot be avoided
5797 Deg1_Elements.splice(Deg1_Elements.begin(), union_of_facets);
5798
5799 setComputed(ConeProperty::Deg1Elements);
5800 }
5801
5802 //---------------------------------------------------------------------------
5803 template <typename Integer>
5804 void Full_Cone<Integer>::compute_HB_via_automs() {
5805 compute_automorphisms(descent_level);
5806
5807 if (!do_Hilbert_basis || isComputed(ConeProperty::HilbertBasis) || !isComputed(ConeProperty::Automorphisms) ||
5808 Automs.getOrder() == 1)
5809 return;
5810
5811 prepare_old_candidates_and_support_hyperplanes();
5812
5813 set<vector<Integer>> union_of_facets; // collects all candidates from the orbits of the HBs of the facets
5814 vector<Integer> fixed_point = get_fixed_point(descent_level); // this is the number of cone points so far
5815
5816 if (verbose) {
5817 verboseOutput() << "Computing Hilbert basis via automorphisms in codim " << descent_level << endl;
5818 verboseOutput() << "Fixed point " << fixed_point;
5819 }
5820
5821 vector<vector<key_t>> facet_keys = get_facet_keys_for_orbits(fixed_point, false);
5822
5823 for (auto& facet_key : facet_keys) {
5824 list<vector<Integer>> facet_HB;
5825 key_t facet_nr = facet_key.back();
5826 facet_key.pop_back();
5827 get_cone_over_facet_vectors(fixed_point, facet_key, facet_nr, facet_HB);
5828
5829 CandidateList<Integer> Cands_from_facet; // first we sort out the reducible elements
5830 for (const auto& jj : facet_HB)
5831 Cands_from_facet.reduce_by_and_insert(jj, *this, OldCandidates);
5832
5833 // set<vector<Integer> > union_of_orbits; // we must spread the irreducibles over their orbit
5834 for (const auto& c : Cands_from_facet.Candidates) {
5835 auto fc = union_of_facets.find(c.cand);
5836 if (fc != union_of_facets.end())
5837 continue;
5838 list<vector<Integer>> orbit_of_cand = Automs.orbit_primal(c.cand);
5839 for (const auto& cc : orbit_of_cand)
5840 union_of_facets.insert(cc);
5841 }
5842 }
5843 cout << "Union unique size " << union_of_facets.size() << endl;
5844 for (const auto& v : union_of_facets)
5845 NewCandidates.push_back(Candidate<Integer>(v, *this));
5846 update_reducers(true); // we always want reduction
5847 OldCandidates.extract(Hilbert_Basis);
5848 Hilbert_Basis.sort();
5849 Hilbert_Basis.unique();
5850
5851 setComputed(ConeProperty::HilbertBasis);
5852
5853 if (isComputed(ConeProperty::Grading)) {
5854 select_deg1_elements();
5855 check_deg1_hilbert_basis();
5856 }
5857 }
5858
5859 //---------------------------------------------------------------------------
5860 template <typename Integer>
5861 vector<Integer> Full_Cone<Integer>::get_fixed_point(size_t nr_cone_points) {
5862 // find fixed ppoint of low degree
5863
5864 size_t mini = 0;
5865 key_t min_orbit = 0;
5866 for (size_t i = 0; i < Automs.GenOrbits.size(); ++i)
5867 if ((mini == 0 || Automs.GenOrbits[i].size() < mini) && Automs.GenOrbits[i][0] >= nr_cone_points) {
5868 mini = Automs.GenOrbits[i].size();
5869 min_orbit = i;
5870 }
5871 vector<Integer> fixed_point(dim);
5872 Matrix<Integer> Extreme_Rays = Generators.submatrix(Extreme_Rays_Ind);
5873 // Extreme_Rays.pretty_print(cout);
5874 for (size_t i = 0; i < Automs.GenOrbits[min_orbit].size(); ++i) {
5875 fixed_point = v_add(fixed_point, Extreme_Rays[Automs.GenOrbits[min_orbit][i]]);
5876 }
5877 v_make_prime(fixed_point);
5878 return fixed_point;
5879 }
5880
5881 //---------------------------------------------------------------------------
5882 template <typename Integer>
5883 vector<vector<key_t>> Full_Cone<Integer>::get_facet_keys_for_orbits(const vector<Integer>& fixed_point, bool with_orbit_sizes) {
5884 // We collect only the facets that do not contain the fixed point.
5885 // The last one (or two) entries of each key vector are abused for
5886 // (the orbit size and ) the number of the suport hyperplane.
5887 // Everything for the first hyperplane in the orbit.
5888
5889 vector<vector<key_t>> facet_keys;
5890 for (size_t k = 0; k < Automs.LinFormOrbits.size(); ++k) {
5891 key_t facet_nr = Automs.LinFormOrbits[k][0];
5892 assert(facet_nr < nrSupport_Hyperplanes); // for safety
5893 Integer ht = v_scalar_product(fixed_point, Support_Hyperplanes[facet_nr]);
5894 if (ht == 0) // fixed point in facet, does not contribute to multiplicity
5895 continue;
5896 vector<key_t> facet_gens;
5897 for (size_t i = 0; i < nr_gen; ++i) {
5898 if (Extreme_Rays_Ind[i] && v_scalar_product(Generators[i], Support_Hyperplanes[facet_nr]) == 0)
5899 facet_gens.push_back(i);
5900 }
5901 facet_keys.push_back(facet_gens);
5902 if (with_orbit_sizes)
5903 facet_keys.back().push_back(Automs.LinFormOrbits[k].size());
5904 facet_keys.back().push_back(facet_nr);
5905 }
5906 return facet_keys;
5907 }
5908 //---------------------------------------------------------------------------
5909 template <typename Integer>
5910 void Full_Cone<Integer>::compute_multiplicity_via_automs() {
5911 compute_automorphisms(0);
5912
5913 if (!do_multiplicity || isComputed(ConeProperty::Multiplicity) || !isComputed(ConeProperty::Grading) ||
5914 !isComputed(ConeProperty::Automorphisms) || Automs.getOrder() == 1)
5915 return;
5916
5917 vector<Integer> fixed_point = get_fixed_point(0); // no cone points in this case
5918 Integer deg_fixed_point = v_scalar_product(fixed_point, Grading);
5919
5920 vector<vector<key_t>> facet_keys = get_facet_keys_for_orbits(fixed_point, true);
5921
5922 if (verbose) {
5923 verboseOutput() << "Computing multiplicity via automorphisms in codim " << descent_level << endl;
5924 verboseOutput() << "Fixed point " << fixed_point;
5925 }
5926
5927 for (auto& facet_key : facet_keys) {
5928 key_t facet_nr = facet_key.back();
5929 facet_key.pop_back();
5930 Integer ht = v_scalar_product(fixed_point, Support_Hyperplanes[facet_nr]);
5931 long long orbit_size = facet_key.back();
5932 facet_key.pop_back();
5933 multiplicity += convertTo<mpz_class>(orbit_size) * convertTo<mpz_class>(ht) * facet_multiplicity(facet_key) /
5934 convertTo<mpz_class>(deg_fixed_point);
5935 }
5936 setComputed(ConeProperty::Multiplicity);
5937 }
5938
5939
5940 //---------------------------------------------------------------------------
5941 template <typename Integer>
5942 void Full_Cone<Integer>::compute_multiplicity_via_recession_cone() {
5943 Matrix<Integer> Level0Gens(0, dim);
5944 for (size_t i = 0; i < nr_gen; ++i) {
5945 if (gen_levels[i] == 0)
5946 Level0Gens.append(Generators[i]);
5947 }
5948 Sublattice_Representation<Integer> Level0Sub(Level0Gens, true);
5949 Matrix<Integer> RecGens = Level0Sub.to_sublattice(Level0Gens);
5950 Full_Cone<Integer> RecCone(RecGens);
5951 RecCone.Grading = Level0Sub.to_sublattice_dual_no_div(Grading);
5952 RecCone.setComputed(ConeProperty::Grading);
5953 RecCone.do_multiplicity = true;
5954 RecCone.verbose = verbose;
5955 RecCone.copy_autom_params(*this);
5956 if (quality_of_automorphisms == AutomParam::ambient) {
5957 RecCone.Embedding = Level0Sub.getEmbeddingMatrix().multiplication(Embedding);
5958 }
5959 RecCone.compute();
5960 multiplicity = RecCone.multiplicity;
5961 setComputed(ConeProperty::Multiplicity);
5962 }
5963 */
5964
5965 //---------------------------------------------------------------------------
5966
5967 /* deactivated at present
5968 template <typename Integer>
5969 mpq_class Full_Cone<Integer>::facet_multiplicity(const vector<key_t>& facet_key) {
5970 Matrix<Integer> Facet_Gens = Generators.submatrix(facet_key);
5971
5972 if (verbose) {
5973 verboseOutput() << "Finding multiplicity for face of codim " << descent_level + 1 << endl;
5974 }
5975
5976 Sublattice_Representation<Integer> Facet_Sub(Facet_Gens, false);
5977 // By this choice we guarantee that the extreme Rays that generate the facet also
5978 // generate the lattice in which the multiplicity is computed.
5979 // This allows for more efficient isomorphism check.
5980 // The lattice can be smaller than the intersection of the facet with the full lattice.
5981 // We take care of this by mutiplying the computed multiplicity with the external index (see below).
5982
5983 Matrix<Integer> Transformed_Facet_Gens = Facet_Sub.to_sublattice(Facet_Gens);
5984 Full_Cone Facet(Transformed_Facet_Gens);
5985 Facet.verbose = verbose;
5986
5987 Facet.Grading = Facet_Sub.to_sublattice_dual_no_div(Grading);
5988 Facet.setComputed(ConeProperty::Grading);
5989 Facet.Mother = &(*this);
5990 Facet.God_Father = God_Father;
5991 Facet.copy_autom_params(*this);
5992 if (quality_of_automorphisms == AutomParam::ambient) {
5993 Facet.Embedding = Facet_Sub.getEmbeddingMatrix().multiplication(Embedding);
5994 }
5995 Facet.inhomogeneous = inhomogeneous;
5996 if (inhomogeneous) {
5997 Facet.Truncation = Facet_Sub.to_sublattice_dual_no_div(Truncation);
5998 }
5999 Facet.descent_level = descent_level + 1;
6000 Facet.keep_order = true;
6001 Facet.Support_Hyperplanes = Facet_Sub.to_sublattice_dual(Support_Hyperplanes);
6002 Facet.compute();
6003 bool found;
6004 const IsoType<Integer>& face_class = God_Father->FaceClasses.find_type(Facet, found);
6005 if (found) {
6006 if (verbose) {
6007 verboseOutput() << "Found isomorphism class" << endl;
6008 }
6009 mpq_class mmm = face_class.getMultiplicity();
6010 return mmm * Facet_Sub.getExternalIndex();
6011 }
6012 else {
6013 if (verbose) {
6014 verboseOutput() << "New isomorphism class" << endl;
6015 }
6016 Full_Cone Facet_2(Transformed_Facet_Gens);
6017 Facet_2.Automs = Facet.Automs;
6018 Facet_2.setComputed(ConeProperty::Automorphisms);
6019 Facet_2.Extreme_Rays_Ind = Facet.Extreme_Rays_Ind;
6020 Facet_2.setComputed(ConeProperty::ExtremeRays);
6021 Facet_2.Support_Hyperplanes = Facet.Support_Hyperplanes;
6022 Facet_2.nrSupport_Hyperplanes = Facet.nrSupport_Hyperplanes;
6023 Facet_2.setComputed(ConeProperty::SupportHyperplanes);
6024 Facet_2.copy_autom_params(*this);
6025 Facet_2.inhomogeneous = inhomogeneous;
6026 Facet_2.Truncation = Facet.Truncation;
6027 if (quality_of_automorphisms == AutomParam::ambient) {
6028 Facet_2.Embedding = Facet_Sub.getEmbeddingMatrix().multiplication(Embedding);
6029 }
6030 Facet_2.verbose = verbose;
6031 Facet_2.descent_level = descent_level + 1;
6032 Facet_2.Grading = Facet_Sub.to_sublattice_dual_no_div(Grading);
6033 Facet_2.setComputed(ConeProperty::Grading);
6034 Facet_2.Mother = &(*this);
6035 Facet_2.God_Father = God_Father;
6036 Facet_2.do_multiplicity = true;
6037 Facet_2.verbose = true;
6038 Facet_2.autom_codim_mult = autom_codim_mult;
6039 Facet_2.compute();
6040 mpq_class mult_before = Facet_2.multiplicity;
6041 bool added;
6042 God_Father->FaceClasses.add_type(Facet_2, added);
6043 assert(mult_before == Facet_2.multiplicity);
6044 return Facet_2.multiplicity * Facet_Sub.getExternalIndex();
6045 }
6046 }
6047 */
6048
6049 //---------------------------------------------------------------------------
6050
6051 template <typename Integer>
compute_hsop()6052 void Full_Cone<Integer>::compute_hsop() {
6053 vector<long> hsop_deg(dim, 1);
6054 // if all extreme rays are in degree one, there is nothing to compute
6055 if (!isDeg1ExtremeRays()) {
6056 if (verbose) {
6057 verboseOutput() << "Computing heights ... " << flush;
6058 }
6059
6060 vector<bool> choice = Extreme_Rays_Ind;
6061 if (inhomogeneous) {
6062 for (size_t i = 0; i < Generators.nr_of_rows(); i++) {
6063 if (Extreme_Rays_Ind[i] && v_scalar_product(Generators[i], Truncation) != 0) {
6064 choice[i] = false;
6065 }
6066 }
6067 }
6068 Matrix<Integer> ER = Generators.submatrix(choice);
6069 Matrix<Integer> SH = getSupportHyperplanes();
6070 if (inhomogeneous) {
6071 Sublattice_Representation<Integer> recession_lattice(ER, true);
6072 Matrix<Integer> SH_raw = recession_lattice.to_sublattice_dual(SH);
6073 Matrix<Integer> ER_embedded = recession_lattice.to_sublattice(ER);
6074 Full_Cone<Integer> recession_cone(ER_embedded);
6075 recession_cone.Support_Hyperplanes = SH_raw;
6076 recession_cone.dualize_cone();
6077 SH = recession_lattice.from_sublattice_dual(recession_cone.getSupportHyperplanes());
6078 }
6079 vector<size_t> ideal_heights(ER.nr_of_rows(), 1);
6080 // the heights vector is clear in the simplicial case
6081 if (is_simplicial) {
6082 for (size_t j = 0; j < ideal_heights.size(); j++)
6083 ideal_heights[j] = j + 1;
6084 }
6085 else {
6086 list<pair<dynamic_bitset, size_t>> facet_list;
6087 list<vector<key_t>> facet_keys;
6088 vector<key_t> key;
6089 size_t d = dim;
6090 if (inhomogeneous)
6091 d = level0_dim;
6092 assert(d > 0); // we want to use d-1
6093 for (size_t i = SH.nr_of_rows(); i-- > 0;) {
6094 dynamic_bitset new_facet(ER.nr_of_rows());
6095 key.clear();
6096 for (size_t j = 0; j < ER.nr_of_rows(); j++) {
6097 if (v_scalar_product(SH[i], ER[j]) == 0) {
6098 new_facet[new_facet.size() - 1 - j] = 1;
6099 }
6100 else {
6101 key.push_back(j);
6102 }
6103 }
6104 facet_list.push_back(make_pair(new_facet, d - 1));
6105 facet_keys.push_back(key);
6106 }
6107 facet_list.sort(); // should be sorted lex
6108 //~ cout << "FACETS:" << endl;
6109 //~ //cout << "size: " << facet_list.size() << " | " << facet_list << endl;
6110 //~ for (auto jt=facet_list.begin();jt!=facet_list.end();++jt){
6111 //~ cout << jt->first << " | " << jt->second << endl;
6112 //~ }
6113 // cout << "facet non_keys: " << facet_keys << endl;
6114 heights(facet_keys, facet_list, ER.nr_of_rows() - 1, ideal_heights, d - 1);
6115 }
6116 if (verbose) {
6117 verboseOutput() << "done." << endl;
6118 if (!inhomogeneous)
6119 assert(ideal_heights[ER.nr_of_rows() - 1] == dim);
6120 else
6121 assert(ideal_heights[ER.nr_of_rows() - 1] == level0_dim);
6122 verboseOutput() << "Heights vector: " << ideal_heights;
6123 }
6124 vector<Integer> er_deg = ER.MxV(Grading);
6125 hsop_deg = convertTo<vector<long>>(degrees_hsop(er_deg, ideal_heights));
6126 }
6127 if (verbose) {
6128 verboseOutput() << "Degrees of HSOP: " << hsop_deg;
6129 }
6130 Hilbert_Series.setHSOPDenom(hsop_deg);
6131 }
6132
6133 template <>
compute_hsop()6134 void Full_Cone<renf_elem_class>::compute_hsop() {
6135 assert(false);
6136 }
6137
6138 // recursive method to compute the heights
6139 // TODO: at the moment: facets are a parameter. global would be better
6140 template <typename Integer>
heights(list<vector<key_t>> & facet_keys,list<pair<dynamic_bitset,size_t>> faces,size_t index,vector<size_t> & ideal_heights,size_t max_dim)6141 void Full_Cone<Integer>::heights(list<vector<key_t>>& facet_keys,
6142 list<pair<dynamic_bitset, size_t>> faces,
6143 size_t index,
6144 vector<size_t>& ideal_heights,
6145 size_t max_dim) {
6146 // since we count the index backwards, this is the actual nr of the extreme ray
6147
6148 size_t ER_nr = ideal_heights.size() - index - 1;
6149 //~ cout << "starting calculation for extreme ray nr " << ER_nr << endl;
6150 list<pair<dynamic_bitset, size_t>> not_faces;
6151 auto face_it = faces.begin();
6152 for (; face_it != faces.end(); ++face_it) {
6153 if (face_it->first.test(index)) { // check whether index is set
6154 break;
6155 }
6156 // resize not_faces
6157 face_it->first.resize(index);
6158 }
6159 not_faces.splice(not_faces.begin(), faces, faces.begin(), face_it);
6160
6161 auto not_faces_it = not_faces.begin();
6162 // update the heights
6163 if (ER_nr > 0) {
6164 if (!not_faces.empty()) {
6165 ideal_heights[ER_nr] = ideal_heights[ER_nr - 1];
6166 // compute the dimensions of not_faces
6167 vector<bool> choice = Extreme_Rays_Ind;
6168 if (inhomogeneous) {
6169 for (size_t i = 0; i < Generators.nr_of_rows(); i++) {
6170 if (Extreme_Rays_Ind[i] && v_scalar_product(Generators[i], Truncation) != 0) {
6171 choice[i] = false;
6172 }
6173 }
6174 }
6175 Matrix<Integer> ER = Generators.submatrix(choice);
6176 int tn;
6177 if (omp_get_level() == omp_start_level)
6178 tn = 0;
6179 else
6180 tn = omp_get_ancestor_thread_num(omp_start_level + 1);
6181 Matrix<Integer>& Test = Top_Cone->RankTest[tn];
6182 vector<key_t> face_key;
6183 for (; not_faces_it != not_faces.end(); ++not_faces_it) {
6184 if (not_faces_it->second == 0) { // dimension has not yet been computed
6185 // generate the key vector
6186 face_key.resize(0);
6187 for (size_t i = 0; i < not_faces_it->first.size(); ++i) {
6188 if (not_faces_it->first.test(i)) {
6189 face_key.push_back(ER.nr_of_rows() - 1 - i);
6190 }
6191 }
6192 not_faces_it->second = Test.rank_submatrix(ER, face_key);
6193 }
6194 if (not_faces_it->second == max_dim)
6195 break;
6196 }
6197 if (not_faces_it == not_faces.end()) {
6198 --max_dim;
6199 ideal_heights[ER_nr] = ideal_heights[ER_nr - 1] + 1;
6200 }
6201 }
6202 else {
6203 ideal_heights[ER_nr] = ideal_heights[ER_nr - 1] + 1;
6204 --max_dim;
6205 }
6206 }
6207 // we computed all the heights
6208 if (index == 0)
6209 return;
6210 // if inner point, we can skip now
6211
6212 // take the union of all faces not containing the current extreme ray
6213 dynamic_bitset union_faces(index);
6214 not_faces_it = not_faces.begin();
6215 for (; not_faces_it != not_faces.end(); ++not_faces_it) {
6216 union_faces |= not_faces_it->first; // take the union
6217 }
6218 // cout << "Their union: " << union_faces << endl;
6219 // the not_faces now already have a size one smaller
6220 union_faces.resize(index + 1);
6221 list<pair<dynamic_bitset, size_t>> new_faces;
6222 // delete all facets which only consist of the previous extreme rays
6223 auto facet_it = facet_keys.begin();
6224 size_t counter = 0;
6225 while (facet_it != facet_keys.end()) {
6226 INTERRUPT_COMPUTATION_BY_EXCEPTION
6227
6228 counter = 0;
6229 for (size_t i = 0; i < facet_it->size(); i++) {
6230 if (facet_it->at(i) <= ER_nr)
6231 continue;
6232 // now we only have new extreme rays
6233 counter = i;
6234 break;
6235 }
6236 size_t j = ER_nr + 1;
6237 for (; j < ideal_heights.size(); j++) {
6238 if (facet_it->at(counter) != j) { // facet contains the element j
6239 break;
6240 }
6241 else if (counter < facet_it->size() - 1)
6242 counter++;
6243 }
6244 if (j == ideal_heights.size()) {
6245 facet_it = facet_keys.erase(facet_it);
6246 }
6247 else
6248 ++facet_it;
6249 }
6250 facet_it = facet_keys.begin();
6251
6252 // main loop
6253 for (; facet_it != facet_keys.end(); ++facet_it) {
6254 INTERRUPT_COMPUTATION_BY_EXCEPTION
6255
6256 // check whether the facet is contained in the faces not containing the generator
6257 // and the previous generators
6258 // and check whether the generator is in the facet
6259 // check whether intersection with facet contributes
6260 bool not_containing_el = false;
6261 // bool whether the facet contains an element which is NOT in the faces not containing the current extreme ray
6262 bool containing_critical_el = false;
6263 counter = 0;
6264 // cout << "check critical for facet " << *it << endl;
6265 for (size_t i = 0; i < facet_it->size(); i++) {
6266 if (facet_it->at(i) == ER_nr) {
6267 not_containing_el = true;
6268 }
6269 if (facet_it->at(i) <= ER_nr && i < facet_it->size() - 1)
6270 continue;
6271 counter = i; // now we have elements which are bigger than the current extreme ray
6272 if (not_containing_el) {
6273 for (size_t j = ER_nr + 1; j < ideal_heights.size(); j++) {
6274 if (facet_it->at(counter) != j) { // i.e. j is in the facet
6275 if (!union_faces.test(ideal_heights.size() - 1 - j)) {
6276 containing_critical_el = true;
6277 break;
6278 }
6279 }
6280 else if (counter < facet_it->size() - 1)
6281 counter++;
6282 }
6283 }
6284 break;
6285 }
6286 if (not_containing_el && containing_critical_el) { // facet contributes
6287 // cout << "Taking intersections with the facet " << *facet_it << endl;
6288 face_it = faces.begin();
6289 for (; face_it != faces.end(); ++face_it) {
6290 dynamic_bitset intersection(face_it->first);
6291 for (unsigned int i : *facet_it) {
6292 if (i > ER_nr)
6293 intersection.set(ideal_heights.size() - 1 - i, false);
6294 }
6295 intersection.resize(index);
6296 if (intersection.any()) {
6297 // check whether the intersection lies in any of the not_faces
6298 not_faces_it = not_faces.begin();
6299 for (; not_faces_it != not_faces.end(); ++not_faces_it) {
6300 if (intersection.is_subset_of(not_faces_it->first))
6301 break;
6302 }
6303 if (not_faces_it == not_faces.end())
6304 new_faces.push_back(make_pair(intersection, 0));
6305 }
6306 }
6307 }
6308 }
6309 // the new faces need to be sort in lex order anyway. this can be used to reduce operations
6310 // for subset checking
6311 new_faces.sort();
6312 auto outer_it = new_faces.begin();
6313 auto inner_it = new_faces.begin();
6314 for (; outer_it != new_faces.end(); ++outer_it) {
6315 INTERRUPT_COMPUTATION_BY_EXCEPTION
6316
6317 // work with a not-key vector
6318 vector<key_t> face_not_key;
6319 for (size_t i = 0; i < outer_it->first.size(); i++) {
6320 if (!outer_it->first.test(i)) {
6321 face_not_key.push_back(i);
6322 }
6323 }
6324 inner_it = new_faces.begin();
6325 size_t i = 0;
6326 while (inner_it != outer_it) {
6327 i = 0;
6328 for (; i < face_not_key.size(); ++i) {
6329 if (inner_it->first.test(face_not_key[i]))
6330 break; // inner_it has an element which is not in outer_it
6331 }
6332 if (i == face_not_key.size()) {
6333 inner_it = new_faces.erase(inner_it); // inner_it is a subface of outer_it
6334 }
6335 else
6336 ++inner_it;
6337 }
6338 }
6339 new_faces.merge(not_faces);
6340 /*cout << "The new faces: " << endl;
6341 for (const auto& jt : new_faces){
6342 cout << jt.first << " | " << jt.second << endl;
6343 }*/
6344
6345 heights(facet_keys, new_faces, index - 1, ideal_heights, max_dim);
6346 }
6347
6348 template <typename Integer>
convert_polyhedron_to_polytope()6349 void Full_Cone<Integer>::convert_polyhedron_to_polytope() {
6350 if (verbose) {
6351 verboseOutput() << "Converting polyhedron to polytope" << endl;
6352 verboseOutput() << "Pointed since cone over polytope" << endl;
6353 }
6354 pointed = true;
6355 setComputed(ConeProperty::IsPointed);
6356 Full_Cone Polytope(Generators);
6357 Polytope.pointed = true;
6358 Polytope.setComputed(ConeProperty::IsPointed);
6359 Polytope.keep_order = true;
6360 Polytope.Grading = Truncation;
6361 Polytope.setComputed(ConeProperty::Grading);
6362 if (isComputed(ConeProperty::SupportHyperplanes)) {
6363 Polytope.Support_Hyperplanes = Support_Hyperplanes;
6364 Polytope.nrSupport_Hyperplanes = nrSupport_Hyperplanes;
6365 Polytope.setComputed(ConeProperty::SupportHyperplanes);
6366 }
6367 if (isComputed(ConeProperty::ExtremeRays)) {
6368 Polytope.Extreme_Rays_Ind = Extreme_Rays_Ind;
6369 Polytope.setComputed(ConeProperty::ExtremeRays);
6370 }
6371 Polytope.do_deg1_elements = true;
6372 Polytope.verbose = verbose;
6373 Polytope.compute();
6374
6375 if (Polytope.isComputed(ConeProperty::SupportHyperplanes) && !isComputed(ConeProperty::SupportHyperplanes)) {
6376 Support_Hyperplanes = Polytope.Support_Hyperplanes;
6377 nrSupport_Hyperplanes = Polytope.nrSupport_Hyperplanes;
6378 setComputed(ConeProperty::SupportHyperplanes);
6379 }
6380 if (Polytope.isComputed(ConeProperty::ExtremeRays) && !isComputed(ConeProperty::ExtremeRays)) {
6381 Extreme_Rays_Ind = Polytope.Extreme_Rays_Ind;
6382 setComputed(ConeProperty::ExtremeRays);
6383 }
6384 if (Polytope.isComputed(ConeProperty::Deg1Elements)) {
6385 module_rank = Polytope.Deg1_Elements.size();
6386 if (do_Hilbert_basis) {
6387 Hilbert_Basis = Polytope.Deg1_Elements;
6388 setComputed(ConeProperty::HilbertBasis);
6389 }
6390 setComputed(ConeProperty::ModuleRank);
6391 if (isComputed(ConeProperty::Grading)) {
6392 multiplicity = 1; // of the recession cone;
6393 setComputed(ConeProperty::Multiplicity);
6394 if (do_h_vector) {
6395 vector<num_t> hv(1);
6396 typename list<vector<Integer>>::const_iterator hb = Polytope.Deg1_Elements.begin();
6397 for (; hb != Polytope.Deg1_Elements.end(); ++hb) {
6398 size_t deg = convertToLong(v_scalar_product(Grading, *hb));
6399 if (deg + 1 > hv.size())
6400 hv.resize(deg + 1);
6401 hv[deg]++;
6402 }
6403 Hilbert_Series.add(hv, vector<denom_t>());
6404 Hilbert_Series.setShift(convertToLong(shift));
6405 Hilbert_Series.adjustShift();
6406 Hilbert_Series.simplify();
6407 setComputed(ConeProperty::HilbertSeries);
6408 }
6409 }
6410 }
6411 }
6412
6413 template <>
convert_polyhedron_to_polytope()6414 void Full_Cone<renf_elem_class>::convert_polyhedron_to_polytope() {
6415 assert(false);
6416 }
6417
6418 //---------------------------------------------------------------------------
6419
6420 // -s
6421 template <typename Integer>
support_hyperplanes()6422 void Full_Cone<Integer>::support_hyperplanes() {
6423 if (!isComputed(ConeProperty::SupportHyperplanes)) {
6424 sort_gens_by_degree(false); // we do not want to triangulate here
6425 build_top_cone();
6426 }
6427 extreme_rays_and_deg1_check();
6428 if (inhomogeneous) {
6429 find_level0_dim();
6430 if (do_module_rank)
6431 find_module_rank();
6432 }
6433 }
6434
6435 //---------------------------------------------------------------------------
6436 // Checks and auxiliary algorithms
6437 //---------------------------------------------------------------------------
6438
6439 template <typename Integer>
extreme_rays_and_deg1_check()6440 void Full_Cone<Integer>::extreme_rays_and_deg1_check() {
6441 check_pointed();
6442 if (!pointed) {
6443 throw NonpointedException();
6444 }
6445 compute_extreme_rays();
6446 deg1_check();
6447 }
6448
6449 //---------------------------------------------------------------------------
6450
6451 template <typename Integer>
check_given_grading()6452 void Full_Cone<Integer>::check_given_grading() {
6453 if (Grading.size() == 0)
6454 return;
6455
6456 bool positively_graded = true;
6457
6458 if (!isComputed(ConeProperty::Grading)) {
6459 size_t neg_index = 0;
6460 Integer neg_value;
6461 bool nonnegative = true;
6462 vector<Integer> degrees = Generators.MxV(Grading);
6463 for (size_t i = 0; i < degrees.size(); ++i) {
6464 if (degrees[i] <= 0 && (!inhomogeneous || gen_levels[i] == 0)) {
6465 // in the inhomogeneous case: test only generators of tail cone
6466 positively_graded = false;
6467 ;
6468 if (degrees[i] < 0) {
6469 nonnegative = false;
6470 neg_index = i;
6471 neg_value = degrees[i];
6472 }
6473 }
6474 }
6475
6476 if (!nonnegative) {
6477 throw BadInputException("Grading gives negative value " + toString(neg_value) + " for generator " +
6478 toString(neg_index + 1) + "!");
6479 }
6480 }
6481
6482 if (positively_graded) {
6483 setComputed(ConeProperty::Grading);
6484 if (inhomogeneous)
6485 find_grading_inhom();
6486 set_degrees();
6487 }
6488 }
6489
6490 //---------------------------------------------------------------------------
6491
6492 template <typename Integer>
find_grading()6493 void Full_Cone<Integer>::find_grading() {
6494 if (inhomogeneous) // in the inhomogeneous case we do not allow implicit grading
6495 return;
6496
6497 deg1_check(); // trying to find grading under which all generators have the same degree
6498 if (!isComputed(ConeProperty::Grading) && (do_multiplicity || do_deg1_elements || do_h_vector)) {
6499 if (!isComputed(ConeProperty::ExtremeRays)) {
6500 if (verbose) {
6501 verboseOutput() << "Cannot find grading s.t. all generators have the degree 1! Computing Extreme rays first:"
6502 << endl;
6503 }
6504 get_supphyps_from_copy(true);
6505 extreme_rays_and_deg1_check();
6506 if (!pointed) {
6507 throw NonpointedException();
6508 };
6509
6510 // We keep the SupportHyperplanes, so we do not need to recompute them
6511 // for the last generator, and use them to make a global reduction earlier
6512 }
6513 }
6514 }
6515
6516 //---------------------------------------------------------------------------
6517
6518 template <typename Integer>
find_level0_dim()6519 void Full_Cone<Integer>::find_level0_dim() {
6520 if (isComputed(ConeProperty::RecessionRank))
6521 return;
6522
6523 if (!isComputed(ConeProperty::Generators)) {
6524 throw FatalException("Missing Generators.");
6525 }
6526
6527 Matrix<Integer> Help(nr_gen, dim);
6528 for (size_t i = 0; i < nr_gen; ++i)
6529 if (gen_levels[i] == 0)
6530 Help[i] = Generators[i];
6531
6532 ProjToLevel0Quot = Help.kernel(false); // Necessary for the module rank
6533 // For level0_dim the rank of Help would be enough
6534
6535 level0_dim = dim - ProjToLevel0Quot.nr_of_rows();
6536 // level0_dim=Help.rank();
6537
6538 setComputed(ConeProperty::RecessionRank);
6539 }
6540
6541 //---------------------------------------------------------------------------
6542
6543 template <typename Integer>
find_level0_dim_from_HB()6544 void Full_Cone<Integer>::find_level0_dim_from_HB() {
6545 // we use the Hilbert basis if we don't have the extreme reys.
6546 // This is possible if the HB was computed by the dual algorithm.
6547 // Would be enough if we would take the extreme reys of the recession cone,
6548 // but they have not been extracted from the HB
6549
6550 if (isComputed(ConeProperty::RecessionRank))
6551 return;
6552
6553 assert(isComputed(ConeProperty::HilbertBasis));
6554
6555 Matrix<Integer> Help(0, dim);
6556 for (const auto& H : Hilbert_Basis)
6557 if (v_scalar_product(H, Truncation) == 0)
6558 Help.append(H);
6559
6560 ProjToLevel0Quot = Help.kernel(); // Necessary for the module rank
6561 // For level0_dim the rank of Help would be enough
6562
6563 level0_dim = dim - ProjToLevel0Quot.nr_of_rows();
6564
6565 setComputed(ConeProperty::RecessionRank);
6566 }
6567
6568 //---------------------------------------------------------------------------
6569
6570 template <typename Integer>
find_module_rank()6571 void Full_Cone<Integer>::find_module_rank() {
6572 if (isComputed(ConeProperty::ModuleRank))
6573 return;
6574
6575 if (level0_dim == dim) {
6576 module_rank = 0;
6577 setComputed(ConeProperty::ModuleRank);
6578 return;
6579 }
6580 if (isComputed(ConeProperty::HilbertBasis)) {
6581 find_module_rank_from_HB();
6582 return;
6583 }
6584
6585 // size_t HBrank = module_rank;
6586
6587 if (do_module_rank)
6588 find_module_rank_from_proj();
6589
6590 /* if(isComputed(ConeProperty::HilbertBasis))
6591 assert(HBrank==module_rank);
6592 */
6593 }
6594
6595 //---------------------------------------------------------------------------
6596
6597 template <typename Integer>
find_module_rank_from_proj()6598 void Full_Cone<Integer>::find_module_rank_from_proj() {
6599 if (verbose) {
6600 verboseOutput() << "Computing projection to quotient mod level 0" << endl;
6601 }
6602
6603 Matrix<Integer> ProjGen(nr_gen, dim - level0_dim);
6604 for (size_t i = 0; i < nr_gen; ++i) {
6605 ProjGen[i] = ProjToLevel0Quot.MxV(Generators[i]);
6606 }
6607
6608 vector<Integer> GradingProj = ProjToLevel0Quot.transpose().solve_ZZ(Truncation);
6609
6610 Full_Cone<Integer> Cproj(ProjGen);
6611 Cproj.verbose = false;
6612 Cproj.Grading = GradingProj;
6613 Cproj.setComputed(ConeProperty::Grading);
6614 Cproj.do_deg1_elements = true;
6615 Cproj.compute();
6616
6617 module_rank = Cproj.Deg1_Elements.size();
6618 setComputed(ConeProperty::ModuleRank);
6619 return;
6620 }
6621
6622 //---------------------------------------------------------------------------
6623
6624 template <typename Integer>
find_module_rank_from_HB()6625 void Full_Cone<Integer>::find_module_rank_from_HB() {
6626 if (level0_dim == 0) {
6627 module_rank = Hilbert_Basis.size();
6628 setComputed(ConeProperty::ModuleRank);
6629 return;
6630 }
6631
6632 set<vector<Integer>> Quotient;
6633 vector<Integer> v;
6634
6635 // cout << "=======================" << endl;
6636 // ProjToLevel0Quot.print(cout);
6637 // cout << "=======================" << endl;
6638
6639 for (const auto& h : Hilbert_Basis) {
6640 INTERRUPT_COMPUTATION_BY_EXCEPTION
6641
6642 v = ProjToLevel0Quot.MxV(h);
6643 bool zero = true;
6644 for (size_t j = 0; j < v.size(); ++j)
6645 if (v[j] != 0) {
6646 zero = false;
6647 break;
6648 }
6649 if (!zero)
6650 Quotient.insert(v);
6651 }
6652
6653 module_rank = Quotient.size();
6654 setComputed(ConeProperty::ModuleRank);
6655 }
6656
6657 //---------------------------------------------------------------------------
6658
6659 template <typename Integer>
find_grading_inhom()6660 void Full_Cone<Integer>::find_grading_inhom() {
6661 if (Grading.size() == 0 || Truncation.size() == 0) {
6662 throw FatalException("Cannot find grading in the inhomogeneous case!");
6663 }
6664
6665 if (shift != 0) // to avoid double computation
6666 return;
6667
6668 bool first = true;
6669 Integer level, degree, quot = 0, min_quot = 0;
6670 for (size_t i = 0; i < nr_gen; ++i) {
6671 level = v_scalar_product(Truncation, Generators[i]);
6672 if (level == 0)
6673 continue;
6674 degree = v_scalar_product(Grading, Generators[i]);
6675 quot = degree / level;
6676 // cout << Generators[i];
6677 // cout << "*** " << degree << " " << level << " " << quot << endl;
6678 if (level * quot >= degree)
6679 quot--;
6680 if (first) {
6681 min_quot = quot;
6682 first = false;
6683 }
6684 if (quot < min_quot)
6685 min_quot = quot;
6686 // cout << "+++ " << min_quot << endl;
6687 }
6688 shift = min_quot;
6689 for (size_t i = 0; i < dim; ++i) // under this grading all generators have positive degree
6690 Grading[i] = Grading[i] - shift * Truncation[i];
6691
6692 // shift--; // NO LONGER correction for the Hilbert series computation to have it start in degree 0
6693 }
6694
6695 #ifdef ENFNORMALIZ
6696 template <>
find_grading_inhom()6697 void Full_Cone<renf_elem_class>::find_grading_inhom() {
6698 assert(false);
6699 }
6700 #endif
6701
6702 //---------------------------------------------------------------------------
6703
6704 template <typename Integer>
set_levels()6705 void Full_Cone<Integer>::set_levels() {
6706 if (inhomogeneous && Truncation.size() != dim) {
6707 throw FatalException("Truncation not defined in inhomogeneous case.");
6708 }
6709
6710 if (gen_levels.size() != nr_gen) // now we compute the levels
6711 {
6712 gen_levels.resize(nr_gen);
6713 vector<Integer> gen_levels_Integer = Generators.MxV(Truncation);
6714 for (size_t i = 0; i < nr_gen; i++) {
6715 if (gen_levels_Integer[i] < 0) {
6716 throw FatalException("Truncation gives non-positive value " + toString(gen_levels_Integer[i]) +
6717 " for generator " + toString(i + 1) + ".");
6718 }
6719 convert(gen_levels[i], gen_levels_Integer[i]);
6720 // cout << "Gen " << Generators[i];
6721 // cout << "level " << gen_levels[i] << endl << "----------------------" << endl;
6722 }
6723 }
6724 }
6725
6726 //---------------------------------------------------------------------------
6727
6728 template <typename Integer>
sort_gens_by_degree(bool triangulate)6729 void Full_Cone<Integer>::sort_gens_by_degree(bool triangulate) {
6730 // if(deg1_extreme_rays) // gen_degrees.size()==0 ||
6731 // return;
6732
6733 if (keep_order)
6734 return;
6735
6736 /* commented out since only used in exploitation of automorphisms
6737 *
6738 // we first order the generaors by "support hyperplanes" for computations using automorphisms
6739 // in order to have an intrinsic useful sorting
6740 if (isComputed(ConeProperty::SupportHyperplanes) && descent_level > 0) {
6741 Matrix<Integer> TranspType(Support_Hyperplanes.nr_of_rows(), Generators.nr_of_rows());
6742
6743 #pragma omp parallel for
6744 for (size_t i = 0; i < Support_Hyperplanes.nr_of_rows(); ++i)
6745 for (size_t j = 0; j < Generators.nr_of_rows(); ++j)
6746 TranspType[i][j] = v_scalar_product(Support_Hyperplanes[i], Generators[j]);
6747
6748 Matrix<Integer> OrderSupps = TranspType.sort_by_nr_of_zeroes();
6749 Matrix<Integer> Type = TranspType.transpose();
6750 vector<key_t> new_perm = Type.perm_by_lex();
6751 Generators.order_rows_by_perm(new_perm);
6752 compose_perm_gens(new_perm);
6753 if (verbose)
6754 verboseOutput() << "Generators sorted lexicographically by scalar products with support hyperplanes" << endl;
6755 }
6756 */
6757
6758 Matrix<Integer> Weights(0, dim);
6759 vector<bool> absolute;
6760 if (triangulate) {
6761 if (isComputed(ConeProperty::Grading)) {
6762 Weights.append(Grading);
6763 absolute.push_back(false);
6764 }
6765 }
6766
6767 vector<key_t> perm = Generators.perm_by_weights(Weights, absolute);
6768
6769 Generators.order_rows_by_perm(perm);
6770 order_by_perm_bool(Extreme_Rays_Ind, perm);
6771
6772 if (isComputed(ConeProperty::Grading) || (inhomogeneous && using_renf<Integer>() && do_multiplicity)) {
6773 order_by_perm(gen_degrees, perm);
6774 if (do_h_vector || (!using_GMP<Integer>() && !using_renf<Integer>()))
6775 order_by_perm(gen_degrees_long, perm);
6776 }
6777
6778 if (inhomogeneous && gen_levels.size() == nr_gen)
6779 order_by_perm(gen_levels, perm);
6780
6781 if (triangulate) {
6782 Integer roughness;
6783 if (isComputed(ConeProperty::Grading)) {
6784 roughness = gen_degrees[nr_gen - 1] / gen_degrees[0];
6785 }
6786 else {
6787 Integer max_norm = 0, min_norm = 0;
6788 for (size_t i = 0; i < dim; ++i) {
6789 max_norm += Iabs(Generators[nr_gen - 1][i]);
6790 min_norm += Iabs(Generators[0][i]);
6791 }
6792 roughness = max_norm / min_norm;
6793 }
6794 if (verbose) {
6795 verboseOutput() << "Roughness " << roughness << endl;
6796 }
6797
6798 if (roughness >= 10 && !suppress_bottom_dec) {
6799 do_bottom_dec = true;
6800 if (verbose) {
6801 verboseOutput() << "Bottom decomposition activated" << endl;
6802 }
6803 }
6804 }
6805 /*
6806 if (exploit_automs_vectors && descent_level == 0 && isComputed(ConeProperty::Grading)) {
6807 vector<key_t> inverse_order(nr_gen);
6808 for (size_t i = 0; i < nr_gen; ++i)
6809 inverse_order[i] = nr_gen - 1 - i;
6810 vector<key_t> largest_simplex = Generators.max_rank_submatrix_lex(inverse_order);
6811 HB_bound = -1;
6812 for (size_t i = 0; i < dim; ++i)
6813 HB_bound += convertTo<Integer>(gen_degrees[largest_simplex[i]]);
6814 }
6815 */
6816
6817 if (verbose) {
6818 if (triangulate) {
6819 if (isComputed(ConeProperty::Grading)) {
6820 verboseOutput() << "Generators sorted by degree and lexicographically" << endl;
6821 verboseOutput() << "Generators per degree:" << endl;
6822 verboseOutput() << count_in_map<Integer, long>(gen_degrees);
6823 }
6824 else
6825 verboseOutput() << "Generators sorted lexicographically" << endl;
6826 }
6827 else {
6828 verboseOutput() << "Generators sorted lexicographically" << endl;
6829 }
6830 }
6831 keep_order = true;
6832 }
6833
6834 //---------------------------------------------------------------------------
6835
6836 template <typename Integer>
compose_perm_gens(const vector<key_t> & perm)6837 void Full_Cone<Integer>::compose_perm_gens(const vector<key_t>& perm) {
6838 order_by_perm(PermGens, perm);
6839 }
6840
6841 //---------------------------------------------------------------------------
6842
6843 // an alternative to compute() for the basic tasks that need no triangulation
6844 template <typename Integer>
dualize_cone(bool print_message)6845 void Full_Cone<Integer>::dualize_cone(bool print_message) {
6846
6847 InputGenerators = Generators; // purified input -- in case we get an exception
6848
6849 // Safeguard against the removal of input generators despite that extreme rays
6850 // had been computed in the cone.
6851 if(Extreme_Rays_Ind.size()!=0 && Extreme_Rays_Ind.size() != Generators.nr_of_rows()){
6852 is_Computed.reset(ConeProperty::ExtremeRays);
6853 Extreme_Rays_Ind.resize(0);
6854 }
6855
6856 omp_start_level = omp_get_level();
6857
6858 if (dim == 0) {
6859 set_zero_cone();
6860 return;
6861 }
6862
6863 // DO NOT CALL do_vars_check!!
6864
6865 bool save_tri = do_triangulation;
6866 bool save_part_tri = do_partial_triangulation;
6867 /* do_triangulation = false;
6868 do_partial_triangulation = false; */
6869
6870 if (print_message)
6871 start_message();
6872
6873 sort_gens_by_degree(false);
6874
6875 InputGenerators = Generators; // purified input
6876
6877 try{
6878 if (!isComputed(ConeProperty::SupportHyperplanes))
6879 build_top_cone();
6880 } catch (const NonpointedException&) {
6881 };
6882
6883 if(!pointed){ // we get rid of the duplcates now which can be produced in this case
6884 vector<size_t> UniqueIndices = Support_Hyperplanes.remove_duplicate_and_zero_rows();
6885 if(keep_convex_hull_data){ // in this case we must also get rid of duplicate members of Facets
6886 set<key_t> UniquePositions; // go via a set for simplicity
6887 UniquePositions.insert(UniqueIndices.begin(), UniqueIndices.end());
6888 auto F = Facets.begin();
6889 for(size_t i=0; i < Facets.size(); ++i){
6890 if(UniquePositions.find(i) == UniquePositions.end()){
6891 F = Facets.erase(F);
6892 continue;
6893 }
6894 F++;
6895 }
6896 }
6897 }
6898
6899 if (do_extreme_rays) // in case we have known the support hyperplanes
6900 compute_extreme_rays();
6901
6902 do_triangulation = save_tri;
6903 do_partial_triangulation = save_part_tri;
6904 if (print_message)
6905 end_message();
6906 }
6907
6908 //---------------------------------------------------------------------------
6909
6910 template <typename Integer>
find_start_simplex() const6911 vector<key_t> Full_Cone<Integer>::find_start_simplex() const {
6912 return Generators.max_rank_submatrix_lex();
6913 }
6914
6915 //---------------------------------------------------------------------------
6916
6917 /*
6918 template <typename Integer>
6919 Matrix<Integer> Full_Cone<Integer>::select_matrix_from_list(const list<vector<Integer>>& S, vector<size_t>& selection) {
6920 sort(selection.begin(), selection.end());
6921 assert(selection.back() < S.size());
6922 size_t i = 0, j = 0;
6923 size_t k = selection.size();
6924 Matrix<Integer> M(selection.size(), S.front().size());
6925 for (auto ll = S.begin(); ll != S.end() && i < k; ++ll) {
6926 if (j == selection[i]) {
6927 M[i] = *ll;
6928 i++;
6929 }
6930 j++;
6931 }
6932 return M;
6933 }
6934 */
6935 //---------------------------------------------------------------------------
6936
6937 template <typename Integer>
6938
minimize_support_hyperplanes()6939 void Full_Cone<Integer>::minimize_support_hyperplanes() {
6940 if (Support_Hyperplanes.nr_of_rows() == 0) {
6941 return;
6942 }
6943 if (isComputed(ConeProperty::SupportHyperplanes)) {
6944 nrSupport_Hyperplanes = Support_Hyperplanes.nr_of_rows();
6945 return;
6946 }
6947 if (verbose) {
6948 verboseOutput() << "Minimize the given set of support hyperplanes by "
6949 << "computing the extreme rays of the dual cone" << endl;
6950 }
6951 Full_Cone<Integer> Dual(Support_Hyperplanes);
6952 Dual.verbose = false; // verbose;
6953 Dual.Support_Hyperplanes = Generators;
6954 Dual.setComputed(ConeProperty::SupportHyperplanes);
6955 Dual.do_extreme_rays = true;
6956 Dual.compute_extreme_rays();
6957 Support_Hyperplanes = Dual.Generators.submatrix(Dual.Extreme_Rays_Ind); // only essential hyperplanes
6958 setComputed(ConeProperty::SupportHyperplanes);
6959 nrSupport_Hyperplanes = Support_Hyperplanes.nr_of_rows();
6960 do_all_hyperplanes = false;
6961 }
6962
6963 //---------------------------------------------------------------------------
6964
6965 template <typename Integer>
compute_extreme_rays(bool use_facets)6966 void Full_Cone<Integer>::compute_extreme_rays(bool use_facets) {
6967
6968 if(!do_extreme_rays)
6969 return;
6970
6971 if (isComputed(ConeProperty::ExtremeRays))
6972 return;
6973
6974 Extreme_Rays_Ind.resize(nr_gen);
6975
6976 assert(isComputed(ConeProperty::SupportHyperplanes));
6977
6978 check_pointed();
6979 if (!pointed) {
6980 throw NonpointedException();
6981 }
6982
6983 if (dim * Support_Hyperplanes.nr_of_rows() < nr_gen) {
6984 compute_extreme_rays_rank(use_facets);
6985 }
6986 else {
6987 compute_extreme_rays_compare(use_facets);
6988 }
6989 }
6990
6991 //---------------------------------------------------------------------------
6992
6993 template <typename Integer>
compute_extreme_rays_rank(bool use_facets)6994 void Full_Cone<Integer>::compute_extreme_rays_rank(bool use_facets) {
6995 if (verbose)
6996 verboseOutput() << "Select extreme rays via rank ... " << flush;
6997
6998 size_t i;
6999 vector<key_t> gen_in_hyperplanes;
7000 gen_in_hyperplanes.reserve(Support_Hyperplanes.nr_of_rows());
7001 Matrix<Integer> M(Support_Hyperplanes.nr_of_rows(), dim);
7002
7003 deque<bool> Ext(nr_gen, false);
7004 #pragma omp parallel for firstprivate(gen_in_hyperplanes, M)
7005 for (i = 0; i < nr_gen; ++i) {
7006 // if (isComputed(ConeProperty::Triangulation) && !in_triang[i])
7007 // continue;
7008
7009 INTERRUPT_COMPUTATION_BY_EXCEPTION
7010
7011 gen_in_hyperplanes.clear();
7012 if (use_facets) {
7013 typename list<FACETDATA<Integer>>::const_iterator IHV = Facets.begin();
7014 for (size_t j = 0; j < Support_Hyperplanes.nr_of_rows(); ++j, ++IHV) {
7015 if (IHV->GenInHyp.test(i))
7016 gen_in_hyperplanes.push_back(j);
7017 }
7018 }
7019 else {
7020 for (size_t j = 0; j < Support_Hyperplanes.nr_of_rows(); ++j) {
7021 if (v_scalar_product(Generators[i], Support_Hyperplanes[j]) == 0)
7022 gen_in_hyperplanes.push_back(j);
7023 }
7024 }
7025 if (gen_in_hyperplanes.size() < dim - 1)
7026 continue;
7027 if (M.rank_submatrix(Support_Hyperplanes, gen_in_hyperplanes) >= dim - 1)
7028 Ext[i] = true;
7029 }
7030 for (i = 0; i < nr_gen; ++i)
7031 Extreme_Rays_Ind[i] = Ext[i];
7032
7033 setComputed(ConeProperty::ExtremeRays);
7034 if (verbose)
7035 verboseOutput() << "done." << endl;
7036 }
7037
7038 //---------------------------------------------------------------------------
7039
7040 template <typename Integer>
compute_extreme_rays_compare(bool use_facets)7041 void Full_Cone<Integer>::compute_extreme_rays_compare(bool use_facets) {
7042 if (verbose)
7043 verboseOutput() << "Select extreme rays via comparison ... " << flush;
7044
7045 size_t i, j, k;
7046 // Matrix<Integer> SH=getSupportHyperplanes().transpose();
7047 // Matrix<Integer> Val=Generators.multiplication(SH);
7048 size_t nc = Support_Hyperplanes.nr_of_rows();
7049
7050 vector<dynamic_bitset> Val(nr_gen);
7051 for (i = 0; i < nr_gen; ++i)
7052 Val[i].resize(nc);
7053
7054 // In this routine Val[i][j]==1, i.e. true, indicates that
7055 // the i-th generator is contained in the j-th support hyperplane
7056
7057 vector<key_t> Zero(nc);
7058 vector<key_t> nr_ones(nr_gen);
7059
7060 for (i = 0; i < nr_gen; i++) {
7061 INTERRUPT_COMPUTATION_BY_EXCEPTION
7062
7063 k = 0;
7064 Extreme_Rays_Ind[i] = true;
7065 if (use_facets) {
7066 typename list<FACETDATA<Integer>>::const_iterator IHV = Facets.begin();
7067 for (j = 0; j < Support_Hyperplanes.nr_of_rows(); ++j, ++IHV) {
7068 if (IHV->GenInHyp.test(i)) {
7069 k++;
7070 Val[i][j] = true;
7071 }
7072 else
7073 Val[i][j] = false;
7074 }
7075 }
7076 else {
7077 for (j = 0; j < nc; ++j) {
7078 if (v_scalar_product(Generators[i], Support_Hyperplanes[j]) == 0) {
7079 k++;
7080 Val[i][j] = true;
7081 }
7082 else
7083 Val[i][j] = false;
7084 }
7085 }
7086 nr_ones[i] = k;
7087 if (k < dim - 1 || k == nc) // not contained in enough facets or in all (0 as generator)
7088 Extreme_Rays_Ind[i] = false;
7089 }
7090
7091 dynamic_bitset ERI = bool_to_bitset(Extreme_Rays_Ind);
7092 maximal_subsets(Val, ERI);
7093 Extreme_Rays_Ind = bitset_to_bool(ERI);
7094
7095 setComputed(ConeProperty::ExtremeRays);
7096 if (verbose)
7097 verboseOutput() << "done." << endl;
7098 }
7099
7100 //---------------------------------------------------------------------------
7101
7102 template <typename Integer>
compute_class_group()7103 void Full_Cone<Integer>::compute_class_group() { // from the support hyperplanes
7104 if (!do_class_group || !isComputed(ConeProperty::SupportHyperplanes) || isComputed(ConeProperty::ClassGroup) ||
7105 descent_level != 0)
7106 return;
7107 Matrix<Integer> Trans = Support_Hyperplanes; // .transpose();
7108 size_t rk;
7109 Trans.SmithNormalForm(rk);
7110 ClassGroup.push_back(static_cast<unsigned long>(Support_Hyperplanes.nr_of_rows() - rk));
7111 for (size_t i = 0; i < rk; ++i)
7112 if (Trans[i][i] != 1)
7113 ClassGroup.push_back(Trans[i][i]);
7114 setComputed(ConeProperty::ClassGroup);
7115 }
7116
7117 //---------------------------------------------------------------------------
7118
7119 template <typename Integer>
select_deg1_elements()7120 void Full_Cone<Integer>::select_deg1_elements() { // from the Hilbert basis
7121
7122 if (inhomogeneous || descent_level > 0)
7123 return;
7124 for (const auto& h : Hilbert_Basis) {
7125 if (v_scalar_product(Grading, h) == 1)
7126 Deg1_Elements.push_back(h);
7127 }
7128 setComputed(ConeProperty::Deg1Elements, true);
7129 }
7130
7131 //---------------------------------------------------------------------------
7132
7133
7134 template <typename Integer>
subcone_contains(const vector<Integer> & v)7135 bool Full_Cone<Integer>::subcone_contains(const vector<Integer>& v) {
7136 for (size_t i = 0; i < Subcone_Support_Hyperplanes.nr_of_rows(); ++i)
7137 if (v_scalar_product(Subcone_Support_Hyperplanes[i], v) < 0)
7138 return false;
7139 for (size_t i = 0; i < Subcone_Equations.nr_of_rows(); ++i)
7140 if (v_scalar_product(Subcone_Equations[i], v) != 0)
7141 return false;
7142 if (is_global_approximation)
7143 if (v_scalar_product(Subcone_Grading, v) != 1)
7144 return false;
7145
7146 return true;
7147 }
7148
7149 //---------------------------------------------------------------------------
7150
7151
7152 template <typename Integer>
contains(const vector<Integer> & v)7153 bool Full_Cone<Integer>::contains(const vector<Integer>& v) {
7154 for (size_t i = 0; i < Support_Hyperplanes.nr_of_rows(); ++i)
7155 if (v_scalar_product(Support_Hyperplanes[i], v) < 0)
7156 return false;
7157 return true;
7158 }
7159 //---------------------------------------------------------------------------
7160
7161 /*
7162 template <typename Integer>
7163 bool Full_Cone<Integer>::contains(const Full_Cone& C) {
7164 for (size_t i = 0; i < C.nr_gen; ++i)
7165 if (!contains(C.Generators[i])) {
7166 cerr << "Missing generator " << C.Generators[i] << endl;
7167 return (false);
7168 }
7169 return (true);
7170 }
7171 //---------------------------------------------------------------------------
7172
7173 template <typename Integer>
7174 void Full_Cone<Integer>::select_deg1_elements(const Full_Cone& C) { // from vectors computed in
7175 // the auxiliary cone C
7176 assert(isComputed(ConeProperty::SupportHyperplanes));
7177 assert(C.isComputed(ConeProperty::Deg1Elements));
7178 for (const auto& h : C.Deg1_Elements) {
7179 if (contains(h))
7180 Deg1_Elements.push_back(h);
7181 }
7182 setComputed(ConeProperty::Deg1Elements, true);
7183 }
7184
7185 */
7186 //---------------------------------------------------------------------------
7187
7188 // so far only for experiments
7189 /*
7190 template<typename Integer>
7191 void Full_Cone<Integer>::select_Hilbert_Basis(const Full_Cone& C) { // from vectors computed in
7192 // the auxiliary cone C
7193 assert(isComputed(ConeProperty::SupportHyperplanes));
7194 assert(C.isComputed(ConeProperty::Deg1Elements));
7195 typename list<vector<Integer> >::const_iterator h = C.Hilbert_Basis.begin();
7196 for(;h!=C.Hilbert_Basis.end();++h){
7197 if(contains(*h))
7198 // Deg1_Elements.push_back(*h);
7199 cout << *h;
7200 }
7201 exit(0);
7202 setComputed(ConeProperty::Deg1Elements,true);
7203 }
7204 */
7205
7206 //---------------------------------------------------------------------------
7207
7208 template <typename Integer>
check_pointed()7209 void Full_Cone<Integer>::check_pointed() {
7210
7211 if(believe_pointed){ // sometimes we must cheat
7212 pointed = true;
7213 setComputed(ConeProperty::IsPointed);
7214 return;
7215
7216 }
7217 if (isComputed(ConeProperty::IsPointed))
7218 return;
7219 assert(isComputed(ConeProperty::SupportHyperplanes));
7220 if (isComputed(ConeProperty::Grading)) {
7221 pointed = true;
7222 if (verbose)
7223 verboseOutput() << "Pointed since graded" << endl;
7224 setComputed(ConeProperty::IsPointed);
7225 return;
7226 }
7227 if (verbose)
7228 verboseOutput() << "Checking pointedness ... " << flush;
7229 if (Support_Hyperplanes.nr_of_rows() <= dim * dim / 2) {
7230 pointed = (Support_Hyperplanes.rank() == dim);
7231 }
7232 else{
7233 vector<key_t> random_perm= random_key(Support_Hyperplanes.nr_of_rows());
7234 pointed = (Support_Hyperplanes.max_rank_submatrix_lex().size() == dim);
7235 }
7236 setComputed(ConeProperty::IsPointed);
7237 if (pointed && Grading.size() > 0) {
7238 throw BadInputException("Grading not positive on pointed cone.");
7239 }
7240 if (verbose)
7241 verboseOutput() << "done." << endl;
7242 }
7243
7244 //---------------------------------------------------------------------------
7245 template <typename Integer>
disable_grading_dep_comp()7246 void Full_Cone<Integer>::disable_grading_dep_comp() {
7247 if (do_multiplicity || do_deg1_elements || do_h_vector) {
7248 if (do_default_mode) {
7249 do_deg1_elements = false;
7250 do_h_vector = false;
7251 if (!explicit_full_triang) {
7252 do_triangulation = false;
7253 if (do_Hilbert_basis)
7254 do_partial_triangulation = true;
7255 }
7256 }
7257 else {
7258 throw NotComputableException("No grading specified and cannot find one. Cannot compute some requested properties!");
7259 }
7260 }
7261 }
7262
7263 //---------------------------------------------------------------------------
7264
7265 template <typename Integer>
deg1_check()7266 void Full_Cone<Integer>::deg1_check() {
7267 if (inhomogeneous) // deg 1 check disabled since it makes no sense in this case
7268 return;
7269
7270 if (!isComputed(ConeProperty::Grading) && Grading.size() == 0 // we still need it and
7271 && !isComputed(ConeProperty::IsDeg1ExtremeRays)) { // we have not tried it
7272 if (isComputed(ConeProperty::ExtremeRays)) {
7273 Matrix<Integer> Extreme = Generators.submatrix(Extreme_Rays_Ind);
7274 if (has_generator_with_common_divisor)
7275 Extreme.make_prime();
7276 try {
7277 Grading = Extreme.find_linear_form();
7278 } catch (const ArithmeticException& e) { // if the exception has been thrown, the grading has
7279 Grading.resize(0); // we consider the grafing as non existing -- though this may not be true
7280 if (verbose)
7281 verboseOutput() << "Giving up the check for a grading" << endl;
7282 }
7283
7284 if (Grading.size() == dim && v_scalar_product(Grading, Extreme[0]) == 1) {
7285 setComputed(ConeProperty::Grading);
7286 }
7287 else {
7288 deg1_extreme_rays = false;
7289 Grading.clear();
7290 setComputed(ConeProperty::IsDeg1ExtremeRays);
7291 }
7292 }
7293 else // extreme rays not known
7294 if (!deg1_generated_computed) {
7295 Matrix<Integer> GenCopy = Generators;
7296 if (has_generator_with_common_divisor)
7297 GenCopy.make_prime();
7298 try {
7299 Grading = GenCopy.find_linear_form();
7300 } catch (const ArithmeticException& e) { // if the exception has been thrown,
7301 Grading.resize(0); // we consider the grafing as non existing-- though this may not be true
7302 if (verbose)
7303 verboseOutput() << "Giving up the check for a grading" << endl;
7304 }
7305 if (Grading.size() == dim && v_scalar_product(Grading, GenCopy[0]) == 1) {
7306 setComputed(ConeProperty::Grading);
7307 }
7308 else {
7309 deg1_generated = false;
7310 deg1_generated_computed = true;
7311 Grading.clear();
7312 }
7313 }
7314 }
7315
7316 // now we hopefully have a grading
7317
7318 if (!isComputed(ConeProperty::Grading)) {
7319 if (isComputed(ConeProperty::ExtremeRays)) {
7320 // there is no hope to find a grading later
7321 deg1_generated = false;
7322 deg1_generated_computed = true;
7323 deg1_extreme_rays = false;
7324 setComputed(ConeProperty::IsDeg1ExtremeRays);
7325 disable_grading_dep_comp();
7326 }
7327 return; // we are done
7328 }
7329
7330 set_degrees();
7331
7332 vector<Integer> divided_gen_degrees = gen_degrees;
7333 if (has_generator_with_common_divisor) {
7334 Matrix<Integer> GenCopy = Generators;
7335 GenCopy.make_prime();
7336 convert(divided_gen_degrees, GenCopy.MxV(Grading));
7337 }
7338
7339 if (!deg1_generated_computed) {
7340 deg1_generated = true;
7341 for (size_t i = 0; i < nr_gen; i++) {
7342 if (divided_gen_degrees[i] != 1) {
7343 deg1_generated = false;
7344 break;
7345 }
7346 }
7347 deg1_generated_computed = true;
7348 if (deg1_generated) {
7349 deg1_extreme_rays = true;
7350 setComputed(ConeProperty::IsDeg1ExtremeRays);
7351 }
7352 }
7353 if (!isComputed(ConeProperty::IsDeg1ExtremeRays) && isComputed(ConeProperty::ExtremeRays)) {
7354 deg1_extreme_rays = true;
7355 for (size_t i = 0; i < nr_gen; i++) {
7356 if (Extreme_Rays_Ind[i] && divided_gen_degrees[i] != 1) {
7357 deg1_extreme_rays = false;
7358 break;
7359 }
7360 }
7361 setComputed(ConeProperty::IsDeg1ExtremeRays);
7362 }
7363 }
7364
7365 //---------------------------------------------------------------------------
7366
7367 template <typename Integer>
check_deg1_hilbert_basis()7368 void Full_Cone<Integer>::check_deg1_hilbert_basis() {
7369 if (isComputed(ConeProperty::IsDeg1HilbertBasis) || inhomogeneous || descent_level > 0)
7370 return;
7371
7372 if (!isComputed(ConeProperty::Grading) || !isComputed(ConeProperty::HilbertBasis)) {
7373 if (verbose) {
7374 errorOutput() << "WARNING: unsatisfied preconditions in check_deg1_hilbert_basis()!" << endl;
7375 }
7376 return;
7377 }
7378
7379 if (isComputed(ConeProperty::Deg1Elements)) {
7380 deg1_hilbert_basis = (Deg1_Elements.size() == Hilbert_Basis.size());
7381 }
7382 else {
7383 deg1_hilbert_basis = true;
7384 for (const auto& h : Hilbert_Basis) {
7385 if (v_scalar_product(h, Grading) != 1) {
7386 deg1_hilbert_basis = false;
7387 break;
7388 }
7389 }
7390 }
7391 setComputed(ConeProperty::IsDeg1HilbertBasis);
7392 }
7393
7394 //---------------------------------------------------------------------------
7395
7396 template <typename Integer>
prepare_inclusion_exclusion()7397 void Full_Cone<Integer>::prepare_inclusion_exclusion() {
7398 if (ExcludedFaces.nr_of_rows() == 0)
7399 return;
7400
7401 do_excluded_faces = do_h_vector || do_Stanley_dec || check_semiopen_empty;
7402
7403 if ((isComputed(ConeProperty::ExcludedFaces) && isComputed(ConeProperty::InclusionExclusionData)) || !do_excluded_faces) {
7404 return;
7405 }
7406
7407 if(verbose)
7408 verboseOutput() << "Computing inclusion/excluseion data" << endl;
7409
7410 // indicates which generators lie in the excluded faces
7411 vector<dynamic_bitset> GensInExcl(ExcludedFaces.nr_of_rows());
7412
7413 index_covering_face = ExcludedFaces.nr_of_rows(); // if not changed: not covered by an exc luded face
7414
7415 for (size_t j = 0; j < ExcludedFaces.nr_of_rows(); ++j) {
7416 bool empty_semiopen = true;
7417 GensInExcl[j].resize(nr_gen);
7418 for (size_t i = 0; i < nr_gen; ++i) {
7419 Integer test = v_scalar_product(ExcludedFaces[j], Generators[i]);
7420 if (test == 0) {
7421 GensInExcl[j].set(i);
7422 continue;
7423 }
7424 empty_semiopen = false;
7425 }
7426 if (empty_semiopen) { // not impossible if the hyperplane contains the vector space spanned by the cone
7427 if(!check_semiopen_empty || do_h_vector || do_Stanley_dec)
7428 throw BadInputException("An Excluded face covers the polyhedron. Not allowed unless ONLY checking emptyness.");
7429 empty_semiopen = true;
7430 index_covering_face = j;
7431 setComputed(ConeProperty::IsEmptySemiOpen);
7432 setComputed(ConeProperty::ExcludedFaces);
7433 return;
7434 }
7435 }
7436
7437 if(check_semiopen_empty){
7438 setComputed(ConeProperty::IsEmptySemiOpen);
7439 }
7440
7441 vector<bool> essential(ExcludedFaces.nr_of_rows(), true);
7442 bool remove_one = false;
7443 for (size_t i = 0; i < essential.size(); ++i)
7444 for (size_t j = i + 1; j < essential.size(); ++j) {
7445 if (GensInExcl[j].is_subset_of(GensInExcl[i])) {
7446 essential[j] = false;
7447 remove_one = true;
7448 continue;
7449 }
7450 if (GensInExcl[i].is_subset_of(GensInExcl[j])) {
7451 essential[i] = false;
7452 remove_one = true;
7453 }
7454 }
7455 if (remove_one) {
7456 Matrix<Integer> Help(0, dim);
7457 vector<dynamic_bitset> HelpGensInExcl;
7458 for (size_t i = 0; i < essential.size(); ++i)
7459 if (essential[i]) {
7460 Help.append(ExcludedFaces[i]);
7461 HelpGensInExcl.push_back(GensInExcl[i]);
7462 }
7463 ExcludedFaces = Help;
7464 GensInExcl = HelpGensInExcl;
7465 }
7466 setComputed(ConeProperty::ExcludedFaces);
7467
7468 if (isComputed(ConeProperty::InclusionExclusionData) || !do_excluded_faces) {
7469 return;
7470 }
7471
7472 vector<pair<dynamic_bitset, long>> InExScheme; // now we produce the formal
7473 dynamic_bitset all_gens(nr_gen); // inclusion-exclusion scheme
7474 all_gens.set(); // by forming all intersections of
7475 // excluded faces
7476 InExScheme.push_back(pair<dynamic_bitset, long>(all_gens, 1));
7477 size_t old_size = 1;
7478
7479 for (size_t i = 0; i < ExcludedFaces.nr_of_rows(); ++i) {
7480 for (size_t j = 0; j < old_size; ++j)
7481 InExScheme.push_back(pair<dynamic_bitset, long>(InExScheme[j].first & GensInExcl[i], -InExScheme[j].second));
7482 old_size *= 2;
7483 }
7484
7485 InExScheme.erase(InExScheme.begin()); // remove full cone
7486
7487 // map<dynamic_bitset, long> InExCollect;
7488 InExCollect.clear();
7489
7490 for (size_t i = 0; i < old_size - 1; ++i) { // we compactify the list of faces
7491 auto F = InExCollect.find(InExScheme[i].first); // obtained as intersections
7492 if (F != InExCollect.end()) // by listing each face only once
7493 F->second += InExScheme[i].second; // but with the right multiplicity
7494 else
7495 InExCollect.insert(InExScheme[i]);
7496 }
7497
7498 for (auto F = InExCollect.begin(); F != InExCollect.end();) { // faces with multiplicity 0
7499 if (F->second == 0) // can be erased
7500 InExCollect.erase(F++);
7501 else {
7502 ++F;
7503 }
7504 }
7505
7506 if (verbose) {
7507 verboseOutput() << endl;
7508 verboseOutput() << "InEx complete, " << InExCollect.size() << " faces involved" << endl;
7509 }
7510
7511 setComputed(ConeProperty::InclusionExclusionData);
7512 }
7513
7514 //---------------------------------------------------------------------------
7515
7516 /*
7517 template <typename Integer>
7518
7519 bool Full_Cone<Integer>::check_extension_to_god_father() {
7520 assert(dim == God_Father->dim);
7521 vector<Integer> test(dim);
7522 for (size_t k = 0; k < Automs.LinMaps.size(); ++k) {
7523 for (size_t i = 0; i < God_Father->nr_gen; ++i) {
7524 test = Automs.LinMaps[k].MxV(God_Father->Generators[i]);
7525 if (God_Father->Generator_Set.find(test) == God_Father->Generator_Set.end())
7526 return false;
7527 }
7528 }
7529 return true;
7530 }
7531 */
7532
7533 //---------------------------------------------------------------------------
7534
7535 /* computes a degree function, s.t. every generator has value >0 */
7536 template <typename Integer>
compute_degree_function() const7537 vector<Integer> Full_Cone<Integer>::compute_degree_function() const {
7538 size_t i;
7539 vector<Integer> degree_function(dim, 0);
7540 if (isComputed(ConeProperty::Grading)) { // use the grading if we have one
7541 for (i = 0; i < dim; i++) {
7542 degree_function[i] = Grading[i];
7543 }
7544 }
7545 else { // add hyperplanes to get a degree function
7546 if (verbose) {
7547 verboseOutput() << "computing degree function... " << flush;
7548 }
7549 size_t h;
7550 for (h = 0; h < Support_Hyperplanes.nr_of_rows(); ++h) {
7551 for (i = 0; i < dim; i++) {
7552 degree_function[i] += Support_Hyperplanes.get_elem(h, i);
7553 }
7554 }
7555
7556 v_make_prime(degree_function);
7557 if (verbose) {
7558 verboseOutput() << "done." << endl;
7559 }
7560 }
7561 return degree_function;
7562 }
7563
7564 //---------------------------------------------------------------------------
7565
7566 /* adds generators, they have to lie inside the existing cone */
7567 template <typename Integer>
add_generators(const Matrix<Integer> & new_points)7568 void Full_Cone<Integer>::add_generators(const Matrix<Integer>& new_points) {
7569 is_simplicial = false;
7570 int nr_new_points = new_points.nr_of_rows();
7571 int nr_old_gen = nr_gen;
7572 Generators.append(new_points);
7573 nr_gen += nr_new_points;
7574 set_degrees();
7575 Top_Key.resize(nr_gen);
7576 Extreme_Rays_Ind.resize(nr_gen);
7577 for (size_t i = nr_old_gen; i < nr_gen; ++i) {
7578 Top_Key[i] = i;
7579 Extreme_Rays_Ind[i] = false;
7580 }
7581 // inhom cones
7582 if (inhomogeneous) {
7583 set_levels();
7584 }
7585 // excluded faces have to be reinitialized
7586 setComputed(ConeProperty::ExcludedFaces, false);
7587 setComputed(ConeProperty::InclusionExclusionData, false);
7588 prepare_inclusion_exclusion();
7589
7590 if (do_Hilbert_basis) {
7591 // add new points to HilbertBasis
7592 for (size_t i = nr_old_gen; i < nr_gen; ++i) {
7593 if (!inhomogeneous || gen_levels[i] <= 1) {
7594 NewCandidates.reduce_by_and_insert(Generators[i], *this, OldCandidates);
7595 NewCandidates.Candidates.back().original_generator = true;
7596 }
7597 }
7598 // OldCandidates.auto_reduce();
7599 }
7600 }
7601
7602 //---------------------------------------------------------------------------
7603 // Constructors
7604 //---------------------------------------------------------------------------
7605
7606 template <typename Integer>
reset_tasks()7607 void Full_Cone<Integer>::reset_tasks() {
7608 do_triangulation_size = false;
7609 do_determinants = false;
7610 do_multiplicity = false;
7611 do_integrally_closed = false;
7612 do_Hilbert_basis = false;
7613 do_deg1_elements = false;
7614 keep_triangulation = false;
7615 pulling_triangulation = false;
7616 keep_triangulation_bitsets = false;
7617 do_Stanley_dec = false;
7618 do_h_vector = false;
7619 do_hsop = false;
7620 do_excluded_faces = false;
7621 do_approximation = false;
7622 do_default_mode = false;
7623 do_class_group = false;
7624 do_module_gens_intcl = false;
7625 do_module_rank = false;
7626 do_cone_dec = false;
7627 do_extreme_rays = false;
7628 do_pointed = false;
7629 do_all_hyperplanes = true;
7630 do_supphyps_dynamic = false;
7631
7632 check_semiopen_empty = false;
7633
7634 do_bottom_dec = false;
7635 keep_order = false;
7636
7637 nrSimplicialPyr = 0;
7638 totalNrPyr = 0;
7639 is_pyramid = false;
7640
7641 exploit_automs_vectors = false;
7642 exploit_automs_mult = false;
7643 do_automorphisms = false;
7644 autom_codim_vectors = -1;
7645 autom_codim_mult = -1;
7646
7647 use_existing_facets = false;
7648
7649 triangulation_is_nested = false;
7650 triangulation_is_partial = false;
7651
7652 hilbert_basis_rec_cone_known = false;
7653 time_measured = false;
7654
7655 keep_convex_hull_data = false;
7656
7657 do_multiplicity_by_signed_dec = false;
7658 do_integral_by_signed_dec = false;
7659 do_signed_dec = false;
7660 do_virtual_multiplicity_by_signed_dec = false;
7661 do_pure_triang = false;
7662
7663 believe_pointed = false;
7664 include_dualization = false;
7665
7666 pyramids_for_last_built_directly = false;
7667 }
7668
7669 //---------------------------------------------------------------------------
7670
7671 template <typename Integer>
Full_Cone()7672 Full_Cone<Integer>::Full_Cone() {
7673 reset_tasks();
7674 }
7675
7676 template <typename Integer>
Full_Cone(const Matrix<Integer> & M,bool do_make_prime)7677 Full_Cone<Integer>::Full_Cone(const Matrix<Integer>& M, bool do_make_prime) { // constructor of the top cone
7678
7679 omp_start_level = omp_get_level();
7680
7681 dim = M.nr_of_columns();
7682 if (dim > 0)
7683 Generators = M;
7684
7685
7686 /* cout << "------------------" << endl;
7687 cout << "dim " << dim << endl;
7688 M.pretty_print(cout);
7689 // cout << "------------------" << endl;
7690 // M.transpose().pretty_print(cout);
7691 cout << "==================" << endl;*/
7692
7693
7694 // assert(M.row_echelon()== dim); rank check now done later
7695
7696 /*index=1; // not used at present
7697 for(size_t i=0;i<dim;++i)
7698 index*=M[i][i];
7699 index=Iabs(index); */
7700
7701 // make the generators coprime, remove 0 rows and duplicates
7702 has_generator_with_common_divisor = false;
7703 if (do_make_prime) {
7704 Generators.make_prime();
7705 }
7706 else {
7707 nr_gen = Generators.nr_of_rows();
7708 for (size_t i = 0; i < nr_gen; ++i) {
7709 if (v_gcd(Generators[i]) != 1) {
7710 has_generator_with_common_divisor = true;
7711 break;
7712 }
7713 }
7714 }
7715 Generators.remove_duplicate_and_zero_rows();
7716
7717 nr_gen = Generators.nr_of_rows();
7718
7719 if (nr_gen != static_cast<size_t>(static_cast<key_t>(nr_gen))) {
7720 throw FatalException("Too many generators to fit in range of key_t!");
7721 }
7722
7723 multiplicity = 0;
7724 #ifdef ENFNORMALIZ
7725 renf_multiplicity = 0;
7726 #endif
7727 is_Computed = bitset<ConeProperty::EnumSize>(); // initialized to false
7728 setComputed(ConeProperty::Generators);
7729 pointed = false;
7730 is_simplicial = nr_gen == dim;
7731 deg1_extreme_rays = false;
7732 deg1_generated = false;
7733 deg1_generated_computed = false;
7734 deg1_hilbert_basis = false;
7735
7736 reset_tasks();
7737
7738 Extreme_Rays_Ind = vector<bool>(nr_gen, false); // now in compute_extreme_eays
7739 // in_triang = vector<bool> (nr_gen,false); // now in build_cone
7740 deg1_triangulation = true;
7741 /*
7742 if(dim==0){ //correction needed to include the 0 cone;
7743 multiplicity = 1;
7744 #ifdef ENFNORMALIZ
7745 renf_multiplicity=1;
7746 #endif
7747 Hilbert_Series.add(vector<num_t>(1,1),vector<denom_t>());
7748 setComputed(ConeProperty::HilbertSeries);
7749 setComputed(ConeProperty::Triangulation);
7750 }
7751 */
7752 pyr_level = -1;
7753 descent_level = 0;
7754 Top_Cone = this;
7755 // God_Father = this;
7756 Top_Key.resize(nr_gen);
7757 for (size_t i = 0; i < nr_gen; i++)
7758 Top_Key[i] = i;
7759 totalNrSimplices = 0;
7760 TriangulationBufferSize = 0;
7761 CandidatesSize = 0;
7762 detSum = 0;
7763 shift = 0;
7764 decimal_digits = -1;
7765 block_size_hollow_tri = -1;
7766
7767 FS.resize(omp_get_max_threads());
7768
7769 Pyramids.resize(20); // prepare storage for pyramids
7770 nrPyramids.resize(20, 0);
7771 Pyramids_scrambled.resize(20, false);
7772
7773 recursion_allowed = true;
7774
7775 // nextGen=0;
7776 store_level = 0;
7777
7778 Comparisons.reserve(nr_gen);
7779 nrTotalComparisons = 0;
7780
7781 inhomogeneous = false;
7782
7783 level0_dim = dim; // must always be defined
7784
7785 start_from = 0;
7786 old_nr_supp_hyps = 0;
7787
7788 verbose = false;
7789 OldCandidates.dual = false;
7790 OldCandidates.verbose = verbose;
7791 NewCandidates.dual = false;
7792 NewCandidates.verbose = verbose;
7793
7794 RankTest = vector<Matrix<Integer>>(omp_get_max_threads(), Matrix<Integer>(0, dim));
7795 RankTest_float = vector<Matrix<nmz_float>>(omp_get_max_threads(), Matrix<nmz_float>(0, dim));
7796 UnitMat = Matrix<Integer>(dim);
7797 WorkMat = vector<Matrix<Integer> >(omp_get_max_threads(), Matrix<Integer>(dim, 2*dim));
7798
7799 do_bottom_dec = false;
7800 suppress_bottom_dec = false;
7801 keep_order = false;
7802
7803 is_global_approximation = false;
7804
7805 PermGens.resize(nr_gen);
7806 for (size_t i = 0; i < nr_gen; ++i)
7807 PermGens[i] = i;
7808
7809 Mother = &(*this);
7810
7811 don_t_add_hyperplanes = false;
7812 take_time_of_large_pyr = false;
7813
7814 renf_degree = 2; // default value to prevent desasters
7815 }
7816
7817 //---------------------------------------------------------------------------
7818 // converts a Cone_Dual_Mode into a Full_Cone
7819 template <typename Integer>
Full_Cone(Cone_Dual_Mode<Integer> & C)7820 Full_Cone<Integer>::Full_Cone(Cone_Dual_Mode<Integer>& C) {
7821 omp_start_level = omp_get_level();
7822
7823 is_Computed = bitset<ConeProperty::EnumSize>(); // initialized to false
7824
7825 dim = C.dim;
7826 Generators.swap(C.Generators);
7827 InputGenerators = Generators;
7828 nr_gen = Generators.nr_of_rows();
7829 if (Generators.nr_of_rows() > 0)
7830 setComputed(ConeProperty::Generators);
7831 has_generator_with_common_divisor = false;
7832 Extreme_Rays_Ind.swap(C.ExtremeRaysInd);
7833 if (!Extreme_Rays_Ind.empty())
7834 setComputed(ConeProperty::ExtremeRays);
7835
7836 multiplicity = 0;
7837
7838 #ifdef ENFNORMALIZ
7839 renf_multiplicity = 0;
7840 #endif
7841 in_triang = vector<bool>(nr_gen, false);
7842
7843 Basis_Max_Subspace = C.BasisMaxSubspace;
7844 setComputed(ConeProperty::MaximalSubspace);
7845 pointed = (Basis_Max_Subspace.nr_of_rows() == 0);
7846 setComputed(ConeProperty::IsPointed);
7847 is_simplicial = nr_gen == dim;
7848 deg1_extreme_rays = false;
7849 deg1_generated = false;
7850 deg1_generated_computed = false;
7851 deg1_triangulation = false;
7852 deg1_hilbert_basis = false;
7853
7854 reset_tasks();
7855
7856 if (!Extreme_Rays_Ind.empty()) { // only then we can assume that all entries on C.Supp.. are relevant
7857 Support_Hyperplanes.swap(C.SupportHyperplanes);
7858 // there may be duplicates in the coordinates of the Full_Cone
7859 Support_Hyperplanes.remove_duplicate_and_zero_rows();
7860 setComputed(ConeProperty::SupportHyperplanes);
7861 }
7862 if (!C.do_only_Deg1_Elements) {
7863 Hilbert_Basis.swap(C.Hilbert_Basis);
7864 setComputed(ConeProperty::HilbertBasis);
7865 }
7866 else {
7867 Deg1_Elements.swap(C.Hilbert_Basis);
7868 setComputed(ConeProperty::Deg1Elements);
7869 }
7870 if (dim == 0) { // correction needed to include the 0 cone;
7871 multiplicity = 1;
7872 #ifdef ENFNORMALIZ
7873 renf_multiplicity = 1;
7874 #endif
7875 Hilbert_Series.add(vector<num_t>(1, 1), vector<denom_t>());
7876 setComputed(ConeProperty::HilbertSeries);
7877 }
7878 pyr_level = -1;
7879 Top_Cone = this;
7880 // God_Father = this;
7881 Top_Key.resize(nr_gen);
7882 for (size_t i = 0; i < nr_gen; i++)
7883 Top_Key[i] = i;
7884 totalNrSimplices = 0;
7885 TriangulationBufferSize = 0;
7886 CandidatesSize = 0;
7887 detSum = 0;
7888 shift = 0;
7889
7890 tri_recursion = false;
7891
7892 // nextGen=0;
7893
7894 inhomogeneous = C.inhomogeneous;
7895
7896 level0_dim = dim; // must always be defined
7897
7898 use_existing_facets = false;
7899 start_from = 0;
7900 old_nr_supp_hyps = 0;
7901 verbose = C.verbose;
7902 OldCandidates.dual = false;
7903 OldCandidates.verbose = verbose;
7904 NewCandidates.dual = false;
7905 NewCandidates.verbose = verbose;
7906
7907 descent_level = 0;
7908 // approx_level = 1; ???? Noch gebraucht ???
7909
7910 don_t_add_hyperplanes = false;
7911 take_time_of_large_pyr = false;
7912
7913 verbose = C.verbose;
7914 }
7915
7916 //---------------------------------------------------------------------------
7917
7918 template <typename Integer>
check_grading_after_dual_mode()7919 void Full_Cone<Integer>::check_grading_after_dual_mode() {
7920 if (dim > 0 && Grading.size() > 0 && !isComputed(ConeProperty::Grading)) {
7921 if (isComputed(ConeProperty::Generators)) {
7922 vector<Integer> degrees = Generators.MxV(Grading);
7923 vector<Integer> levels;
7924 if (inhomogeneous)
7925 levels = Generators.MxV(Truncation);
7926 size_t i = 0;
7927 for (; i < degrees.size(); ++i) {
7928 if (degrees[i] <= 0 && (!inhomogeneous || levels[i] == 0))
7929 break;
7930 }
7931 if (i == degrees.size())
7932 setComputed(ConeProperty::Grading);
7933 }
7934 else if (isComputed(ConeProperty::HilbertBasis)) {
7935 auto hb = Hilbert_Basis.begin();
7936 for (; hb != Hilbert_Basis.end(); ++hb) {
7937 if (v_scalar_product(*hb, Grading) <= 0 && (!inhomogeneous || v_scalar_product(*hb, Truncation) == 0))
7938 break;
7939 }
7940 if (hb == Hilbert_Basis.end())
7941 setComputed(ConeProperty::Grading);
7942 }
7943 }
7944 if (isComputed(ConeProperty::Deg1Elements)) {
7945 auto hb = Deg1_Elements.begin();
7946 for (; hb != Deg1_Elements.end(); ++hb) {
7947 if (v_scalar_product(*hb, Grading) <= 0)
7948 break;
7949 }
7950 if (hb == Deg1_Elements.end())
7951 setComputed(ConeProperty::Grading);
7952 }
7953
7954 if (Grading.size() > 0 && !isComputed(ConeProperty::Grading)) {
7955 throw BadInputException("Grading not positive on pointed cone.");
7956 }
7957 }
7958
7959 template <typename Integer>
dual_mode()7960 void Full_Cone<Integer>::dual_mode() {
7961 omp_start_level = omp_get_level();
7962
7963 if (dim == 0) {
7964 set_zero_cone();
7965 return;
7966 }
7967
7968 use_existing_facets = false; // completely irrelevant here
7969 start_from = 0;
7970 old_nr_supp_hyps = 0;
7971
7972 INTERRUPT_COMPUTATION_BY_EXCEPTION
7973
7974 compute_class_group();
7975
7976 check_grading_after_dual_mode();
7977
7978 compute_automorphisms();
7979
7980 if (dim > 0 && !inhomogeneous) {
7981 deg1_check();
7982 if (isComputed(ConeProperty::Grading) && !isComputed(ConeProperty::Deg1Elements)) {
7983 if (verbose) {
7984 verboseOutput() << "Find degree 1 elements" << endl;
7985 }
7986 select_deg1_elements();
7987 }
7988 }
7989
7990 if (!inhomogeneous && isComputed(ConeProperty::HilbertBasis)) {
7991 if (isComputed(ConeProperty::Grading))
7992 check_deg1_hilbert_basis();
7993 }
7994
7995 if (inhomogeneous && isComputed(ConeProperty::Generators)) {
7996 set_levels();
7997 find_level0_dim();
7998 find_module_rank();
7999 }
8000
8001 if (inhomogeneous && !isComputed(ConeProperty::Generators) && isComputed(ConeProperty::HilbertBasis)) {
8002 find_level0_dim_from_HB();
8003 find_module_rank();
8004 }
8005
8006 use_existing_facets = false;
8007 start_from = 0;
8008 }
8009
8010 //---------------------------------------------------------------------------
8011
8012 /* constructor for pyramids */
8013 template <typename Integer>
Full_Cone(Full_Cone<Integer> & C,const vector<key_t> & Key)8014 Full_Cone<Integer>::Full_Cone(Full_Cone<Integer>& C, const vector<key_t>& Key) {
8015 omp_start_level = C.omp_start_level;
8016 Generators = C.Generators.submatrix(Key);
8017 if (using_renf<Integer>() && C.Generators_float.nr_of_rows() > 0)
8018 Generators_float = C.Generators_float.submatrix(Key);
8019 dim = Generators.nr_of_columns();
8020 nr_gen = Generators.nr_of_rows();
8021 has_generator_with_common_divisor = C.has_generator_with_common_divisor;
8022 is_simplicial = nr_gen == dim;
8023
8024 Top_Cone = C.Top_Cone; // relate to top cone
8025 // C.God_Father = C.God_Father;
8026 Top_Key.resize(nr_gen);
8027 for (size_t i = 0; i < nr_gen; i++)
8028 Top_Key[i] = C.Top_Key[Key[i]];
8029
8030 multiplicity = 0;
8031 #ifdef ENFNORMALIZ
8032 renf_multiplicity = 0;
8033 #endif
8034
8035 Extreme_Rays_Ind = vector<bool>(nr_gen, false);
8036 setComputed(ConeProperty::ExtremeRays, C.isComputed(ConeProperty::ExtremeRays));
8037 if (isComputed(ConeProperty::ExtremeRays))
8038 for (size_t i = 0; i < nr_gen; i++)
8039 Extreme_Rays_Ind[i] = C.Extreme_Rays_Ind[Key[i]];
8040 // in_triang = vector<bool> (nr_gen,false); // now in build_cone
8041 deg1_triangulation = true;
8042
8043 Grading = C.Grading;
8044 setComputed(ConeProperty::Grading, C.isComputed(ConeProperty::Grading));
8045 Order_Vector = C.Order_Vector;
8046
8047 // Note: For the computation of pyramids we do not call primal_algorithm.
8048 // Therefore it is necessary to set do_triangulation etc. here (and not only
8049 // the computation goals).
8050 do_triangulation = C.do_triangulation;
8051 do_partial_triangulation = C.do_partial_triangulation;
8052 do_only_multiplicity = C.do_only_multiplicity;
8053 stop_after_cone_dec = C.stop_after_cone_dec;
8054
8055 // now the computation goals
8056 do_extreme_rays = false;
8057 do_triangulation_size = C.do_triangulation;
8058 do_determinants = C.do_determinants;
8059 do_multiplicity = C.do_multiplicity;
8060 do_deg1_elements = C.do_deg1_elements;
8061 do_h_vector = C.do_h_vector;
8062 do_Hilbert_basis = C.do_Hilbert_basis;
8063 keep_triangulation = C.keep_triangulation;
8064 keep_triangulation_bitsets = C.keep_triangulation_bitsets;
8065 do_pure_triang = C.do_pure_triang;
8066 do_evaluation = C.do_evaluation;
8067 do_Stanley_dec = C.do_Stanley_dec;
8068 do_bottom_dec = false;
8069 keep_order = true;
8070 do_all_hyperplanes = true; // must be reset for non-recursive pyramids
8071 use_existing_facets = false;
8072 do_supphyps_dynamic = false;
8073 pulling_triangulation = false;
8074
8075 pyramids_for_last_built_directly = false;
8076
8077 // not used in a pyramid, but set for precaution
8078 deg1_extreme_rays = false;
8079 deg1_generated = false;
8080 deg1_generated_computed = false;
8081 deg1_hilbert_basis = false;
8082 inhomogeneous = C.inhomogeneous; // at present not used in proper pyramids
8083
8084 is_pyramid = true;
8085
8086 pyr_level = C.pyr_level + 1;
8087 descent_level = 0; // should never be used in pyramids
8088 store_level = C.store_level;
8089
8090 totalNrSimplices = 0;
8091 detSum = 0;
8092 multiplicity = 0;
8093 shift = C.shift;
8094 level0_dim = C.level0_dim; // must always be defined
8095
8096 if (C.gen_degrees.size() > 0) { // now we copy the degrees
8097 gen_degrees.resize(nr_gen);
8098 if (C.do_h_vector || (!using_GMP<Integer>() && !using_renf<Integer>()))
8099 gen_degrees_long.resize(nr_gen);
8100 for (size_t i = 0; i < nr_gen; i++) {
8101 gen_degrees[i] = C.gen_degrees[Key[i]];
8102 if (C.do_h_vector || (!using_GMP<Integer>() && !using_renf<Integer>()))
8103 gen_degrees_long[i] = C.gen_degrees_long[Key[i]];
8104 }
8105 }
8106 if (C.gen_levels.size() > 0) { // now we copy the levels
8107 gen_levels.resize(nr_gen);
8108 for (size_t i = 0; i < nr_gen; i++) {
8109 gen_levels[i] = C.gen_levels[Key[i]];
8110 }
8111 }
8112
8113 TriangulationBufferSize = 0; // not used in pyramids
8114 CandidatesSize = 0; // ditto
8115
8116 recursion_allowed = C.recursion_allowed; // must be reset if necessary
8117 // multithreaded_pyramid=false; // SEE ABOVE
8118
8119 Comparisons.reserve(nr_gen);
8120 nrTotalComparisons = 0;
8121
8122 start_from = 0;
8123 old_nr_supp_hyps = 0;
8124 verbose = false;
8125 OldCandidates.dual = false;
8126 OldCandidates.verbose = verbose;
8127 NewCandidates.dual = false;
8128 NewCandidates.verbose = verbose;
8129
8130 is_global_approximation = C.is_global_approximation;
8131
8132 do_bottom_dec = false;
8133 suppress_bottom_dec = false;
8134 keep_order = true;
8135
8136 time_measured = C.time_measured;
8137 ticks_comp_per_supphyp = C.ticks_comp_per_supphyp;
8138 ticks_rank_per_row = C.ticks_rank_per_row;
8139
8140 don_t_add_hyperplanes = false;
8141 take_time_of_large_pyr = false;
8142 renf_degree = C.renf_degree;
8143 }
8144
8145 //---------------------------------------------------------------------------
8146
8147 template <typename Integer>
isComputed(ConeProperty::Enum prop) const8148 bool Full_Cone<Integer>::isComputed(ConeProperty::Enum prop) const {
8149 return is_Computed.test(prop);
8150 }
8151
8152 template <typename Integer>
setComputed(ConeProperty::Enum prop)8153 void Full_Cone<Integer>::setComputed(ConeProperty::Enum prop) {
8154 is_Computed.set(prop);
8155 }
8156
8157 template <typename Integer>
setComputed(ConeProperty::Enum prop,bool value)8158 void Full_Cone<Integer>::setComputed(ConeProperty::Enum prop, bool value) {
8159 is_Computed.set(prop, value);
8160 }
8161 //---------------------------------------------------------------------------
8162 // Data access
8163 //---------------------------------------------------------------------------
8164
8165 template <typename Integer>
getDimension() const8166 size_t Full_Cone<Integer>::getDimension() const {
8167 return dim;
8168 }
8169
8170 //---------------------------------------------------------------------------
8171
8172 template <typename Integer>
getNrGenerators() const8173 size_t Full_Cone<Integer>::getNrGenerators() const {
8174 return nr_gen;
8175 }
8176
8177 //---------------------------------------------------------------------------
8178
8179 template <typename Integer>
isPointed() const8180 bool Full_Cone<Integer>::isPointed() const {
8181 return pointed;
8182 }
8183
8184 //---------------------------------------------------------------------------
8185
8186 template <typename Integer>
isDeg1ExtremeRays() const8187 bool Full_Cone<Integer>::isDeg1ExtremeRays() const {
8188 return deg1_extreme_rays;
8189 }
8190
8191 template <typename Integer>
isDeg1HilbertBasis() const8192 bool Full_Cone<Integer>::isDeg1HilbertBasis() const {
8193 return deg1_hilbert_basis;
8194 }
8195
8196 //---------------------------------------------------------------------------
8197
8198 template <typename Integer>
getGrading() const8199 vector<Integer> Full_Cone<Integer>::getGrading() const {
8200 return Grading;
8201 }
8202
8203 //---------------------------------------------------------------------------
8204
8205 template <typename Integer>
getMultiplicity() const8206 mpq_class Full_Cone<Integer>::getMultiplicity() const {
8207 return multiplicity;
8208 }
8209
8210 //---------------------------------------------------------------------------
8211
8212 template <typename Integer>
getShift() const8213 Integer Full_Cone<Integer>::getShift() const {
8214 return shift;
8215 }
8216
8217 //---------------------------------------------------------------------------
8218
8219 template <typename Integer>
getModuleRank() const8220 size_t Full_Cone<Integer>::getModuleRank() const {
8221 return module_rank;
8222 }
8223
8224 //---------------------------------------------------------------------------
8225
8226 template <typename Integer>
getGenerators() const8227 const Matrix<Integer>& Full_Cone<Integer>::getGenerators() const {
8228 return InputGenerators;
8229 }
8230
8231 //---------------------------------------------------------------------------
8232
8233 template <typename Integer>
getExtremeRays() const8234 vector<bool> Full_Cone<Integer>::getExtremeRays() const {
8235 vector<bool> ext = Extreme_Rays_Ind;
8236 ext.resize(InputGenerators.nr_of_rows());
8237 return ext;
8238 }
8239
8240 //---------------------------------------------------------------------------
8241
8242 template <typename Integer>
getNrExtremeRays() const8243 size_t Full_Cone<Integer>::getNrExtremeRays() const {
8244 size_t n = 0;
8245 for (size_t j = 0; j < nr_gen; ++j)
8246 if (Extreme_Rays_Ind[j])
8247 ++n;
8248 return n;
8249 }
8250
8251 //---------------------------------------------------------------------------
8252
8253 template <typename Integer>
getSupportHyperplanes() const8254 Matrix<Integer> Full_Cone<Integer>::getSupportHyperplanes() const {
8255 return Support_Hyperplanes;
8256 }
8257
8258 //---------------------------------------------------------------------------
8259
8260 template <typename Integer>
getHilbertBasis() const8261 Matrix<Integer> Full_Cone<Integer>::getHilbertBasis() const {
8262 if (Hilbert_Basis.empty())
8263 return Matrix<Integer>(0, dim);
8264 else
8265 return Matrix<Integer>(Hilbert_Basis);
8266 }
8267
8268 //---------------------------------------------------------------------------
8269
8270 template <typename Integer>
getModuleGeneratorsOverOriginalMonoid() const8271 Matrix<Integer> Full_Cone<Integer>::getModuleGeneratorsOverOriginalMonoid() const {
8272 if (ModuleGeneratorsOverOriginalMonoid.empty())
8273 return Matrix<Integer>(0, dim);
8274 else
8275 return Matrix<Integer>(ModuleGeneratorsOverOriginalMonoid);
8276 }
8277
8278 //---------------------------------------------------------------------------
8279
8280 template <typename Integer>
getDeg1Elements() const8281 Matrix<Integer> Full_Cone<Integer>::getDeg1Elements() const {
8282 if (Deg1_Elements.empty())
8283 return Matrix<Integer>(0, dim);
8284 else
8285 return Matrix<Integer>(Deg1_Elements);
8286 }
8287
8288 //---------------------------------------------------------------------------
8289
8290 template <typename Integer>
getExcludedFaces() const8291 Matrix<Integer> Full_Cone<Integer>::getExcludedFaces() const {
8292 return (ExcludedFaces);
8293 }
8294
8295 //---------------------------------------------------------------------------
8296
8297 template <typename Integer>
error_msg(string s) const8298 void Full_Cone<Integer>::error_msg(string s) const {
8299 errorOutput() << "\nFull Cone " << s << "\n";
8300 }
8301
8302 //---------------------------------------------------------------------------
8303
8304 /*
8305 template <typename Integer>
8306 void Full_Cone<Integer>::print() const {
8307 verboseOutput() << "\ndim=" << dim << ".\n";
8308 verboseOutput() << "\nnr_gen=" << nr_gen << ".\n";
8309 // verboseOutput()<<"\nhyp_size="<<hyp_size<<".\n";
8310 verboseOutput() << "\nGrading is:\n";
8311 verboseOutput() << Grading;
8312 verboseOutput() << "\nMultiplicity is " << multiplicity << ".\n";
8313 verboseOutput() << "\nGenerators are:\n";
8314 Generators.pretty_print(verboseOutput());
8315 verboseOutput() << "\nExtreme_rays are:\n";
8316 verboseOutput() << Extreme_Rays_Ind;
8317 verboseOutput() << "\nSupport Hyperplanes are:\n";
8318 Support_Hyperplanes.pretty_print(verboseOutput());
8319 verboseOutput() << "\nHilbert basis is:\n";
8320 verboseOutput() << Hilbert_Basis;
8321 verboseOutput() << "\nDeg1 elements are:\n";
8322 verboseOutput() << Deg1_Elements;
8323 verboseOutput() << "\nHilbert Series is:\n";
8324 verboseOutput() << Hilbert_Series;
8325 }
8326 */
8327
8328 #ifndef NMZ_MIC_OFFLOAD // offload with long is not supported
8329 template class Full_Cone<long>;
8330 #endif
8331 template class Full_Cone<long long>;
8332 template class Full_Cone<mpz_class>;
8333
8334 #ifdef ENFNORMALIZ
8335 template class Full_Cone<renf_elem_class>;
8336 #endif
8337
8338 // first "hoolow" subfacet in their list coming from the same simplex in the triangulation
8339 template <typename Integer>
first_subfacet(const dynamic_bitset & Subfacet,const bool compute_multiplicity,Matrix<Integer> & PrimalSimplex,mpz_class & MultPrimal,vector<Integer> & DegreesPrimal,Matrix<Integer> & ValuesGeneric)8340 void SignedDec<Integer>::first_subfacet (const dynamic_bitset& Subfacet, const bool compute_multiplicity, Matrix<Integer>& PrimalSimplex,
8341 mpz_class& MultPrimal, vector<Integer>& DegreesPrimal, Matrix<Integer>& ValuesGeneric){
8342
8343 size_t g = 0; // select generators in subfacet
8344 Matrix<Integer> DualSimplex(dim,dim);
8345 for(size_t i=0; i< nr_gen; ++i){
8346 if(Subfacet[i] == 1){
8347 DualSimplex[g] = Generators[i];
8348 g++;
8349 }
8350 }
8351 DualSimplex[dim-1]=Generic;
8352
8353 Integer MultDual;
8354 DualSimplex.simplex_data(identity_key(dim), PrimalSimplex, MultDual, true);
8355
8356 if(compute_multiplicity){
8357 DegreesPrimal = PrimalSimplex.MxV(GradingOnPrimal);
8358 mpz_class ProductOfHeights = 1;
8359 for(size_t i = 0; i < dim; ++i){
8360 ProductOfHeights *= convertTo<mpz_class>(v_scalar_product(PrimalSimplex[i], DualSimplex[i]));
8361 }
8362 MultPrimal = ProductOfHeights/convertTo<mpz_class>(MultDual);
8363 }
8364 else{ // we want to find a generic vector
8365 for(size_t i=0; i< 2; i++)
8366 ValuesGeneric[i] = PrimalSimplex.MxV(CandidatesGeneric[i]);
8367 }
8368 }
8369
8370 template <typename Integer>
next_subfacet(const dynamic_bitset & Subfacet_next,const dynamic_bitset & Subfacet_start,const Matrix<Integer> & PrimalSimplex,const bool compute_multiplicity,const mpz_class & MultPrimal,mpz_class & NewMult,const vector<Integer> & DegreesPrimal,vector<Integer> & NewDegrees,const Matrix<Integer> & ValuesGeneric,Matrix<Integer> & NewValues)8371 void SignedDec<Integer>::next_subfacet(const dynamic_bitset& Subfacet_next, const dynamic_bitset& Subfacet_start,
8372 const Matrix<Integer>& PrimalSimplex, const bool compute_multiplicity,
8373 const mpz_class& MultPrimal, mpz_class& NewMult,
8374 const vector<Integer>& DegreesPrimal, vector<Integer>& NewDegrees,
8375 const Matrix<Integer>& ValuesGeneric, Matrix<Integer>& NewValues){
8376
8377 size_t new_vert;
8378 size_t old_place = 0; // this is the place of i in the ascending sequence of generators in Subfacet_start
8379 size_t g = 0;
8380 for(size_t i = 0; i < nr_gen; ++i){
8381 if(Subfacet_next[i] && !Subfacet_start[i])
8382 new_vert = i;
8383 if(!Subfacet_next[i] && Subfacet_start[i]){
8384 old_place = g;
8385 }
8386 if(Subfacet_start[i])
8387 g++;
8388 }
8389
8390 // We want to replace the "old" Generators[old_vert] corresponding to row old_place
8391 // in PrimalSimplex gy the "new" Generators[new_vert]
8392
8393 // evaluate old linear forms on new vertex
8394 vector<Integer> lambda = PrimalSimplex.MxV(Generators[new_vert]);
8395
8396 // We only need the new degrees. This is a Fourier-Motzkin step.
8397
8398 if(compute_multiplicity){ // we really want to compute multiplicity
8399 for(size_t i = 0; i<dim; ++i){
8400 if(i == old_place) // is already coprime
8401 continue;
8402 NewDegrees[i] = (lambda[i]*DegreesPrimal[old_place]
8403 - lambda[old_place]*DegreesPrimal[i]);
8404 if(!check_range(NewDegrees[i]))
8405 throw ArithmeticException("Overflow in degree computation. Starting with gigger integer class");
8406 }
8407 NewDegrees[old_place] = -DegreesPrimal[old_place];
8408 NewMult = MultPrimal;
8409 // now we update the multiplicity
8410 for(size_t i =0; i< dim-1; ++i){ // corresponds to the virtual multiplication
8411 NewMult *= convertTo<mpz_class>(lambda[old_place]); // of dim-1 rows by lambbda[old_place]
8412 }
8413 NewMult = Iabs(NewMult);
8414 }
8415 else{
8416 for(size_t k = 0; k< 2; ++k){
8417 for(size_t i = 0; i<dim; ++i){
8418 if(i == old_place) // is already coprime
8419 continue;
8420 NewValues[k][i] = (lambda[i]*ValuesGeneric[k][old_place]
8421 - lambda[old_place]*ValuesGeneric[k][i]);
8422 }
8423 NewValues[k][old_place] = -ValuesGeneric[k][old_place];
8424 }
8425 }
8426 }
8427
8428 // This function tries to
8429 // Find a generic element. For this purpose we exchage the role of the generic element and the grading.
8430 // The point is to find an element that does not share a critical hyperplane with the grading. This is a
8431 // syymetric relation. The function becomes 2 candidates in CandisatesGeneric and tries to form a suitable
8432 // linear combination if this is possible at all. It is possible if there is no critical hyperplane (through
8433 // the fraing that contains both candidates. Then it is a matter to find the linear combination
8434 // that lies in none of the hyperplanes. If one is lucky, then one of the candidates is already generic in this sense.
8435
8436 template <typename Integer>
FindGeneric()8437 bool SignedDec<Integer>::FindGeneric(){
8438
8439 bool success = true;
8440
8441 vector< vector<bool> > IsGeneric(omp_get_max_threads(),vector<bool> (2,true));
8442 Matrix<Integer> Quot_tn(omp_get_max_threads(),2);
8443 vector<Integer> Quot(2);
8444
8445 long RelBound = 10000;
8446 #ifdef NMZ_EXTENDED_TESTS
8447 if(test_small_pyramids)
8448 RelBound = 1;
8449 #endif
8450 vector<deque<bool> > Relations(RelBound+1, deque<bool> (RelBound+1,true)); // deque because of parallelization
8451
8452 if(verbose){
8453 verboseOutput() << "Trying to find generic linear combination of " << endl;
8454 CandidatesGeneric.pretty_print(verboseOutput());
8455 }
8456
8457 mpz_class Dummy_mpz; // used in place of the multiplicities that are not computed here
8458 Matrix<Integer> Dummy_mat;
8459 vector<Integer> Dummy_vec;
8460
8461 bool skip_remaining = false;
8462 std::exception_ptr tmp_exception;
8463
8464 #pragma omp parallel
8465 {
8466
8467 Matrix<Integer> PrimalSimplex(dim,dim);
8468 Matrix<Integer> ValuesGeneric(2,dim);
8469
8470 size_t ppos = 0;
8471
8472 auto S = SubfacetsBySimplex->begin();
8473 size_t nr_subfacets_by_simplex = SubfacetsBySimplex->size();
8474
8475 int tn = 0;
8476 if (omp_in_parallel())
8477 tn = omp_get_ancestor_thread_num(omp_start_level + 1);
8478
8479 #pragma omp for schedule(dynamic)
8480 for(size_t fac=0; fac < nr_subfacets_by_simplex; ++fac){
8481
8482 if (skip_remaining)
8483 continue;
8484
8485 for (; fac > ppos; ++ppos, ++S)
8486 ;
8487 for (; fac < ppos; --ppos, --S)
8488 ;
8489
8490 try {
8491
8492 if(verbose && fac % 10000 == 0 && fac > 0){
8493 #pragma omp critical(VERBOSE)
8494 {
8495 verboseOutput() << fac << " simplices done " << endl;
8496 }
8497 }
8498
8499 Matrix<Integer> NewValues;
8500 dynamic_bitset Subfacet_start;
8501 bool first = true;
8502
8503 list<dynamic_bitset> SubfacetsOfSimplex; // now we reproduce the subfacets of the hollow triangulation
8504 for(size_t i = 0; i< nr_gen; ++i){ // coming from simplex S
8505 if(S->second[i]){
8506 SubfacetsOfSimplex.push_back(S->first);
8507 SubfacetsOfSimplex.back()[i] = 0;
8508 }
8509 }
8510
8511 for(auto& Subfacet:SubfacetsOfSimplex){
8512
8513 INTERRUPT_COMPUTATION_BY_EXCEPTION
8514
8515 if(first){
8516 first = false;
8517
8518 first_subfacet(Subfacet, false, PrimalSimplex, Dummy_mpz, Dummy_vec, ValuesGeneric);
8519 // computes the first simplex in this walk
8520 Subfacet_start = Subfacet;
8521 NewValues = ValuesGeneric;
8522 }
8523 else{
8524 next_subfacet(Subfacet, Subfacet_start, PrimalSimplex, false, Dummy_mpz, Dummy_mpz,
8525 Dummy_vec, Dummy_vec, ValuesGeneric,NewValues);
8526 }
8527
8528 for(size_t i=0; i < dim; ++i){
8529 bool good = false;
8530 for(size_t k = 0; k< 2; ++k){
8531 if(NewValues[k][i] != 0){
8532 good = true;
8533 // cout << i << " " << k << endl;
8534 }
8535 else{
8536 IsGeneric[tn][k] = false;
8537 }
8538 }
8539 if(!good){ // there is a linear form giving 0 on both candidates !
8540 skip_remaining = true;
8541 #pragma omp flush(skip_remaining)
8542 if(verbose)
8543 verboseOutput() << "Must increase coefficients" << endl;
8544 success = false;
8545 break;
8546 }
8547
8548 if(NewValues[0][i] == 0 || NewValues[1][i] == 0)
8549 continue;
8550 if(NewValues[0][i] < 0)
8551 continue;
8552 if(NewValues[1][i] >0)
8553 continue;
8554 // remaining case: pos at 0, neg at 1
8555 Integer quot = 1 + (-NewValues[1][i])/NewValues[0][i];
8556 if(quot > Quot_tn[tn][0])
8557 Quot_tn[tn][0] = quot;
8558 quot = 1 + NewValues[0][i]/(-NewValues[1][i]);
8559 if(quot > Quot_tn[tn][1])
8560 Quot_tn[tn][1] = quot;
8561
8562 Integer g = libnormaliz::gcd(NewValues[0][i],NewValues[1][i]);
8563 Integer r0 =(- NewValues[1][i])/g;
8564 if(r0 <= RelBound){
8565 Integer r1 = NewValues[0][i]/g;
8566 if(r1 <= RelBound){
8567 long i0 =convertTo<long>(r0);
8568 long i1 = convertTo<long>(r1);
8569 Relations[i0][i1] = false;
8570 }
8571 }
8572
8573 } // for i (coordinates)
8574
8575 if(!success)
8576 break;
8577
8578 } // loop for given simplex
8579
8580 } catch (const std::exception&) {
8581 tmp_exception = std::current_exception();
8582 skip_remaining = true;
8583 #pragma omp flush(skip_remaining)
8584 }
8585
8586 } // for fac
8587
8588 } // parallel
8589
8590 if (!(tmp_exception == 0))
8591 std::rethrow_exception(tmp_exception);
8592
8593 if(!success)
8594 return false;
8595
8596 //cout << IsGeneric;
8597 //Quot_tn.pretty_print(cout);
8598
8599 for(int i=0; i< omp_get_max_threads(); ++i){
8600 for(size_t j=0; j<2; ++j){
8601 if(Quot_tn[i][j] > Quot[j])
8602 Quot[j] = Quot_tn[i][j];
8603 if(!IsGeneric[i][j])
8604 IsGeneric[0][j] = false;
8605 }
8606 }
8607 if(IsGeneric[0][0])
8608 GenericComputed= CandidatesGeneric[0];
8609 else{
8610 if(IsGeneric[0][1])
8611 GenericComputed= CandidatesGeneric[1];
8612 }
8613 if(GenericComputed.size() > 0){
8614 if(verbose)
8615 verboseOutput() << "Generic on the nose" << endl;
8616 return true;
8617 }
8618
8619 // Now we try to find a linear combination by checking the "syzygies" for one that is
8620 // not hit. Success is indicted by "found". The pair (i,j) gives the suitable
8621 // coefficients.
8622 bool found = false;
8623 vector<Integer> Coeff(2);
8624 for(long k=2; k <= 2*RelBound; ++k){
8625 long i_start = 1;
8626 if(k > RelBound)
8627 i_start = k - RelBound +1;
8628 long i_end = k - 1;
8629 if(i_end > RelBound)
8630 i_end = RelBound;
8631 for(long i= i_start; i <=i_end; ++i){
8632 long j = k - i;
8633 if(libnormaliz::gcd(i,j) > 1)
8634 continue;
8635 if(Relations[i][j]){
8636 Coeff[0] = convertTo<Integer>(i);
8637 Coeff[1] = convertTo<Integer>(j);
8638 found = true;
8639 break;
8640 }
8641 } // j
8642 if(found)
8643 break;
8644 }
8645 if(found){
8646 v_scalar_multiplication(CandidatesGeneric[0], Coeff[0]);
8647 v_scalar_multiplication(CandidatesGeneric[1], Coeff[1]);
8648 GenericComputed= CandidatesGeneric[0];
8649 GenericComputed= v_add(GenericComputed, CandidatesGeneric[1]);
8650 if(verbose)
8651 verboseOutput() << "Generic with coeff " << Coeff[0] << " " << Coeff[1] << endl;
8652 return true;
8653 }
8654
8655 // the last resort: multiply one of the two vector by a large factor
8656 // so that the other vector cann be added without creating a zero for one
8657 // of the critical linear forms
8658 int k;
8659 if(Quot[0] <= Quot[1])
8660 k = 0;
8661 else
8662 k = 1;
8663 GenericComputed= CandidatesGeneric[1-k];
8664 v_scalar_multiplication(CandidatesGeneric[k],Quot[k]);
8665 GenericComputed= v_add(GenericComputed, CandidatesGeneric[k]);
8666 if(verbose)
8667 verboseOutput() << "Generic Computed with factor " << Quot[k] << endl;
8668
8669 return true;
8670 }
8671
8672 //-------------------------------------------------------------------------
8673
8674 template <typename Integer>
ComputeMultiplicity()8675 bool SignedDec<Integer>::ComputeMultiplicity(){
8676
8677 // vector<mpq_class> Collect(omp_get_max_threads());
8678 // vector<mpq_class> HelpCollect(omp_get_max_threads());
8679 // vector<int> CountCollect(omp_get_max_threads());
8680
8681 if(decimal_digits > 0)
8682 approximate = true;
8683 approx_denominator =1;
8684 if(approximate){
8685 for(long i= 0; i< decimal_digits; ++i)
8686 approx_denominator *= 10;
8687 }
8688 vector<AdditionPyramid<mpq_class> >Collect(omp_get_max_threads());
8689 vector<mpz_class> Collect_mpz(omp_get_max_threads(),0);
8690 bool success = true;
8691
8692 if(verbose)
8693 verboseOutput() << "Generic " << Generic;
8694
8695 bool skip_remaining = false;
8696 std::exception_ptr tmp_exception;
8697
8698 for(size_t i=0; i<Collect.size(); ++i){
8699 Collect[i].set_capacity(8);
8700
8701 }
8702
8703 #pragma omp parallel
8704 {
8705
8706 Matrix<Integer> PrimalSimplex(dim,dim);
8707 Matrix<Integer> Dummy_mat;
8708
8709 size_t ppos = 0;
8710
8711 auto S = SubfacetsBySimplex->begin();
8712 size_t nr_subfacets_by_simplex = SubfacetsBySimplex->size();
8713
8714 int tn = 0;
8715 if (omp_in_parallel())
8716 tn = omp_get_ancestor_thread_num(omp_start_level + 1);
8717
8718 #pragma omp for schedule(dynamic)
8719 for(size_t fac=0; fac < nr_subfacets_by_simplex; ++fac){
8720
8721 if (skip_remaining)
8722 continue;
8723
8724 for (; fac > ppos; ++ppos, ++S)
8725 ;
8726 for (; fac < ppos; --ppos, --S)
8727 ;
8728
8729 try {
8730
8731 if(verbose && fac % 10000 == 0 && fac > 0){
8732 #pragma omp critical(VERBOSE)
8733 {
8734 verboseOutput() << fac << " simplices done " << endl;
8735 }
8736 }
8737
8738 mpz_class NewMult;
8739 mpz_class MultPrimal;
8740 // dynamic_bitset Subfacet = S->first;
8741
8742 vector<Integer> DegreesPrimal(dim);
8743 vector<Integer> NewDegrees(dim);
8744 dynamic_bitset Subfacet_start;
8745 bool first = true;
8746
8747 list<dynamic_bitset> SubfacetsOfSimplex; // now we reproduce the subfacets of the hollow triangulation
8748 for(size_t i = 0; i< nr_gen; ++i){ // coming from simplex S
8749 if(S->second[i]){
8750 SubfacetsOfSimplex.push_back(S->first);
8751 SubfacetsOfSimplex.back()[i] = 0;
8752 }
8753 }
8754
8755 for(auto& Subfacet:SubfacetsOfSimplex){
8756
8757 INTERRUPT_COMPUTATION_BY_EXCEPTION
8758
8759 if(first){
8760 first = false;
8761 first_subfacet(Subfacet, true, PrimalSimplex, MultPrimal,DegreesPrimal, Dummy_mat);
8762 // computes the first simplex in this walk
8763
8764 Subfacet_start = Subfacet;
8765 NewMult = MultPrimal;
8766 NewDegrees = DegreesPrimal;
8767 }
8768 else{
8769 next_subfacet(Subfacet, Subfacet_start, PrimalSimplex, true, MultPrimal, NewMult,
8770 DegreesPrimal, NewDegrees, Dummy_mat,Dummy_mat);
8771 }
8772
8773 for(size_t i=0;i<dim; ++i){
8774 if(NewDegrees[i]==0){ // should never happen !!!!!!
8775 success = false;
8776 skip_remaining = true;
8777 #pragma omp flush(skip_remaining)
8778 if(verbose)
8779 verboseOutput() << "Vector not generic" << endl;
8780 break;
8781 }
8782 }
8783
8784 if(!success)
8785 break;
8786
8787 mpz_class GradProdPrimal = 1;
8788 for(size_t i=0; i< dim; ++i)
8789 GradProdPrimal*= convertTo<mpz_class>(NewDegrees[i]);
8790 mpz_class NewMult_mpz = convertTo<mpz_class>(NewMult);
8791 if(approximate){
8792 NewMult_mpz *= approx_denominator;
8793 NewMult_mpz /= GradProdPrimal;
8794 Collect_mpz[tn] += NewMult_mpz;
8795 }
8796
8797 else{
8798 mpq_class NewMult_mpq(NewMult_mpz);
8799 NewMult_mpq /= GradProdPrimal;
8800 Collect[tn].add(NewMult_mpq);
8801 }
8802 } // loop for given simplex
8803
8804 } catch (const std::exception&) {
8805 tmp_exception = std::current_exception();
8806 skip_remaining = true;
8807 #pragma omp flush(skip_remaining)
8808 }
8809
8810 } // for fac
8811
8812 } // parallel
8813
8814 if (!(tmp_exception == 0))
8815 std::rethrow_exception(tmp_exception);
8816
8817 vector<mpq_class> ThreadMult(Collect.size());
8818 mpq_class TotalVol;
8819
8820 if(verbose)
8821 verboseOutput() << "Adding multiplicities of threads" << endl;
8822
8823 if(approximate){
8824 mpz_class TotalVol_mpz = 0;
8825 for(size_t tn = 0; tn < Collect_mpz.size();++tn)
8826 TotalVol_mpz += Collect_mpz[tn];
8827 TotalVol = TotalVol_mpz;
8828 TotalVol /= approx_denominator;
8829 }
8830 else{
8831 for(size_t tn = 0; tn < Collect.size();++tn){
8832 ThreadMult[tn] = Collect[tn].sum();
8833 }
8834 TotalVol = vector_sum_cascade(ThreadMult);
8835 }
8836 /* for(size_t tn = 0; tn < Collect.size();++tn){
8837 TotalVol += Collect[tn].sum();
8838 // TotalVol += HelpCollect[tn];
8839 }*/
8840
8841 /*
8842 mpz_class test_den = 1;
8843 for(long i=0; i<=100;++i)
8844 test_den *= 10;
8845 mpz_class mult_num = TotalVol.get_num();
8846 mpz_class mult_den = TotalVol.get_den();
8847 mult_num *= test_den;
8848 mult_num /= mult_den;
8849 cout << "Fixed test num " << endl;
8850 cout << mult_num << endl << endl;
8851 */
8852
8853 multiplicity = TotalVol;
8854 if(verbose){
8855 verboseOutput() << endl << "Mult (before NoGradingDenom correction) " << multiplicity << endl;
8856 verboseOutput() << "Mult (float) " << std::setprecision(12) << mpq_to_nmz_float(multiplicity) << endl;
8857 }
8858
8859 return true;
8860 }
8861
8862
8863
8864 template <typename Integer>
SignedDec(vector<pair<dynamic_bitset,dynamic_bitset>> & SFS,const Matrix<Integer> & Gens,const vector<Integer> Grad,const int osl)8865 SignedDec<Integer>::SignedDec(vector< pair<dynamic_bitset, dynamic_bitset > >& SFS, const Matrix<Integer>& Gens,
8866 const vector<Integer> Grad, const int osl){
8867
8868 SubfacetsBySimplex = &(SFS);
8869 Generators = Gens;
8870 GradingOnPrimal = Grad;
8871 nr_gen = Generators.nr_of_rows();
8872 dim = Generators[0].size();
8873 omp_start_level = osl;
8874 multiplicity = 0;
8875 int_multiplicity = 0;
8876 approximate = false;
8877 }
8878
8879 template <typename Integer>
SignedDec()8880 SignedDec<Integer>::SignedDec(){
8881
8882 }
8883
8884 #ifndef NMZ_MIC_OFFLOAD // offload with long is not supported
8885 template class SignedDec<long>;
8886 #endif
8887 template class SignedDec<long long>;
8888 template class SignedDec<mpz_class>;
8889
8890 } // namespace libnormaliz
8891
8892 /*
8893
8894 //---------------------------------------------------------------------------
8895 // version with isomorphism classes -- has no real effect
8896 template<typename Integer>
8897 void Full_Cone<Integer>::get_cone_over_facet_HB(const vector<Integer>& fixed_point, const vector<key_t>& facet_key,
8898 const key_t facet_nr, list<vector<Integer> >& Facet_HB){
8899
8900
8901 Matrix<Integer> Facet_Gens(0,dim);
8902 Facet_Gens.append(fixed_point);
8903 Facet_Gens.append(Generators.submatrix(facet_key));
8904
8905 for(long i=0;i<descent_level+1;++i)
8906 cout << "$$$$$$ ";
8907 cout << " " << Facet_Gens.nr_of_rows() << endl;
8908 cout << "Height FP over facet " << v_scalar_product(fixed_point,Support_Hyperplanes[facet_nr]) << endl;
8909
8910 Full_Cone ConeOverFacet(Facet_Gens);
8911 ConeOverFacet.verbose=verbose;
8912
8913 if(isComputed(ConeProperty::Grading)){
8914 ConeOverFacet.Grading=Grading;
8915 ConeOverFacet.setComputed(ConeProperty::Grading);
8916 }
8917 ConeOverFacet.descent_level=descent_level+1;
8918 ConeOverFacet.Mother=&(*this);
8919 ConeOverFacet.God_Father=God_Father;
8920 ConeOverFacet.exploit_automorphisms=true;
8921 ConeOverFacet.full_automorphisms=full_automorphisms;
8922 ConeOverFacet.ambient_automorphisms=ambient_automorphisms;
8923 ConeOverFacet.input_automorphisms=input_automorphisms;
8924 ConeOverFacet.Embedding=Embedding;
8925 ConeOverFacet.keep_order=true;
8926 ConeOverFacet.Support_Hyperplanes=push_supphyps_to_cone_over_facet(fixed_point,facet_nr);
8927 // ConeOverFacet.do_Hilbert_basis=true;
8928 ConeOverFacet.compute();
8929 if(ConeOverFacet.isComputed(ConeProperty::HilbertBasis)){
8930 Facet_HB.splice(Facet_HB.begin(),ConeOverFacet.Hilbert_Basis);
8931 return;
8932 }
8933 bool found;
8934 const IsoType<Integer>& face_class=God_Father->FaceClasses.find_type(ConeOverFacet,found);
8935 if(found){
8936 ConeOverFacet.import_HB_from(face_class);
8937 Facet_HB.clear();
8938 Facet_HB.splice(Facet_HB.begin(),ConeOverFacet.Hilbert_Basis);
8939 if(ConeOverFacet.isComputed(ConeProperty::HilbertBasis))
8940 return;
8941 }
8942
8943 Full_Cone Facet_2(Facet_Gens);
8944 Facet_2.Automs=ConeOverFacet.Automs;
8945 Facet_2.setComputed(ConeProperty::Automorphisms);
8946 Facet_2.Embedding=Embedding;
8947 Facet_2.full_automorphisms=full_automorphisms;
8948 Facet_2.ambient_automorphisms=ambient_automorphisms;
8949 Facet_2.input_automorphisms=input_automorphisms;
8950 Facet_2.exploit_automorphisms=true;
8951 Facet_2.keep_order=true;
8952 Facet_2.Extreme_Rays_Ind=ConeOverFacet.Extreme_Rays_Ind;
8953 Facet_2.setComputed(ConeProperty::ExtremeRays);
8954 Facet_2.Support_Hyperplanes=ConeOverFacet.Support_Hyperplanes;
8955 Facet_2.nrSupport_Hyperplanes=ConeOverFacet.nrSupport_Hyperplanes;
8956 Facet_2.setComputed(ConeProperty::SupportHyperplanes);
8957 Facet_2.verbose=verbose;
8958 Facet_2.descent_level=descent_level+1;
8959 Facet_2.full_automorphisms=full_automorphisms;
8960 Facet_2.ambient_automorphisms=ambient_automorphisms;
8961 Facet_2.input_automorphisms=input_automorphisms;
8962 if(isComputed(ConeProperty::Grading)){
8963 Facet_2.Grading=Grading;
8964 Facet_2.setComputed(ConeProperty::Grading);
8965 }
8966 Facet_2.Mother=&(*this);
8967 Facet_2.God_Father=God_Father;
8968 Facet_2.do_Hilbert_basis=true;
8969 Facet_2.compute();
8970 bool added;
8971 God_Father->FaceClasses.add_type(Facet_2, added);
8972 Facet_HB.clear();
8973 Facet_HB.splice(Facet_HB.begin(),Facet_2.Hilbert_Basis);
8974 return;
8975 }
8976 */
8977
8978 //---------------------------------------------------------------------------
8979
8980 /*
8981 // not used at present
8982 template<typename Integer>
8983 void Full_Cone<Integer>::import_HB_from(const IsoType<Integer>& copy){
8984
8985 assert(isComputed(ConeProperty::Automorphisms));
8986
8987 size_t N=copy.getHilbertBasis().nr_of_rows();
8988 if(N==0){
8989 setComputed(ConeProperty::HilbertBasis);
8990 return;
8991 }
8992
8993 assert(Hilbert_Basis.empty());
8994 for(size_t i=0;i<nr_gen;++i)
8995 Hilbert_Basis.push_back(Generators[i]);
8996
8997 vector<key_t> CanBasisKey=Generators.max_rank_submatrix_lex(Automs.CanLabellingGens);
8998 Matrix<Integer> Transform=copy.getCanTransform().multiplication(Generators.submatrix(CanBasisKey));
8999 Integer D=Transform.matrix_gcd();
9000 if(D!=copy.getCanDenom()) // not liftable
9001 return;
9002 Transform.scalar_division(D);
9003 for(size_t i=0;i<N;++i){
9004 Hilbert_Basis.push_back(Transform.VxM(copy.getHilbertBasis()[i]));
9005 }
9006
9007 setComputed(ConeProperty::HilbertBasis);
9008 return;
9009 }
9010 */
9011