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