1 /*
2  * Normaliz
3  * Copyright (C) 2007-2021  W. Bruns, B. Ichim, Ch. Soeger, U. v. d. Ohe
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 #include <cstdlib>
25 #include <list>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <cmath>
29 
30 #include "libnormaliz/cone.h"
31 #include "libnormaliz/vector_operations.h"
32 #include "libnormaliz/project_and_lift.h"
33 // #include "libnormaliz/map_operations.h"
34 // #include "libnormaliz/convert.h"
35 #include "libnormaliz/full_cone.h"
36 #include "libnormaliz/descent.h"
37 #include "libnormaliz/my_omp.h"
38 #include "libnormaliz/output.h"
39 #include "libnormaliz/collection.h"
40 #include "libnormaliz/face_lattice.h"
41 
42 namespace libnormaliz {
43 using namespace std;
44 
45 /*
46 template class FACETDATA<long>;
47 template class FACETDATA<long long>;
48 template class FACETDATA<mpz_class>;
49 #ifdef ENFNORMALIZ
50 template class FACETDATA<renf_elem_class>;
51 #endif
52 */
53 
54 template <typename Integer>
check_length_of_vectors_in_input(const map<InputType,vector<vector<Integer>>> & multi_input_data,size_t dim)55 void check_length_of_vectors_in_input(const map<InputType, vector<vector<Integer> > >&multi_input_data, size_t dim){
56     for (auto& it: multi_input_data){
57         size_t prescribed_length = dim + type_nr_columns_correction(it.first);
58         for(auto& v: it.second){
59             if(v.size() == 0)
60                 throw BadInputException("Vectors of length 0 not allowed in input");
61             if(v.size() != prescribed_length)
62                 throw BadInputException("Inconsistent length of vectors in input");
63         }
64     }
65 }
66 
67 template <typename Integer>
68 template <typename InputNumber>
check_add_input(const map<InputType,vector<vector<InputNumber>>> & multi_add_data)69 void Cone<Integer>::check_add_input(const map<InputType, vector<vector<InputNumber> > >& multi_add_data) {
70     // if(!keep_convex_hull_data)
71     //    throw BadInputException("Additional input only possible if cone is set Dynamic");
72 
73     auto M = multi_add_data.begin();
74 
75     if (multi_add_data.size() > 1)
76         throw BadInputException("Additional input has too many matrices");
77 
78     auto T = M->first;
79     if (!(T == Type::inequalities || T == Type::inhom_inequalities || T == Type::inhom_equations || T == Type::equations ||
80           T == Type::cone || T == Type::vertices || T == Type::subspace))
81         throw BadInputException("Additional input of illegal type");
82 
83     if (!inhomogeneous) {
84         if (T == Type::inhom_inequalities || T == Type::vertices || T == Type::inhom_equations)
85             throw BadInputException("Additional inhomogeneous input only with inhomogeneous original input");
86     }
87     check_consistency_of_dimension(multi_add_data);
88     int inhom_corr = 0;
89     if(inhomogeneous)
90         inhom_corr = 1;
91     check_length_of_vectors_in_input(multi_add_data,dim-inhom_corr);
92 }
93 
94 template <typename Integer>
95 template <typename InputNumber>
check_consistency_of_dimension(const map<InputType,vector<vector<InputNumber>>> & multi_input_data)96 void Cone<Integer>::check_consistency_of_dimension(const map<InputType, vector<vector<InputNumber> > >& multi_input_data) {
97     size_t inhom_corr = 0;
98     if (inhom_input)
99         inhom_corr = 1;
100     auto it = multi_input_data.begin();
101     size_t test_dim;
102     for (; it != multi_input_data.end(); ++it) {
103         /* if(type_is_number(it->first))
104             continue;*/
105         test_dim = it->second.front().size() - type_nr_columns_correction(it->first) + inhom_corr;
106         if (test_dim != dim) {
107             throw BadInputException("Inconsistent dimensions in input!");
108         }
109     }
110 }
111 
nmzfloat_input_to_mpqclass(const map<InputType,vector<vector<nmz_float>>> & multi_input_data)112 map<InputType, vector<vector<mpq_class> > > nmzfloat_input_to_mpqclass(
113     const map<InputType, vector<vector<nmz_float> > >& multi_input_data) {
114     map<InputType, vector<vector<mpq_class> > > multi_input_data_QQ;
115     auto it = multi_input_data.begin();
116     for (; it != multi_input_data.end(); ++it) {
117         vector<vector<mpq_class> > Transfer;
118         for (const auto& j : it->second) {
119             vector<mpq_class> vt;
120             for (double k : j){
121                 vt.push_back(mpq_class(k));
122             }
123             Transfer.push_back(vt);
124         }
125         multi_input_data_QQ[it->first] = Transfer;
126     }
127     return multi_input_data_QQ;
128 }
129 
renf_allowed(InputType input_type)130 bool renf_allowed(InputType input_type) {
131     switch (input_type) {
132         case Type::congruences:
133         case Type::inhom_congruences:
134         case Type::lattice:
135         case Type::cone_and_lattice:
136         case Type::rational_lattice:
137         case Type::normalization:
138         case Type::integral_closure:
139         case Type::offset:
140         case Type::rational_offset:
141         case Type::rees_algebra:
142         case Type::lattice_ideal:
143         case Type::strict_signs:
144         case Type::strict_inequalities:
145         case Type::hilbert_basis_rec_cone:
146         case Type::open_facets:
147             return false;
148             break;
149         default:
150             return true;
151             break;
152     }
153 }
154 
denominator_allowed(InputType input_type)155 bool denominator_allowed(InputType input_type) {
156     switch (input_type) {
157         case Type::congruences:
158         case Type::inhom_congruences:
159         case Type::grading:
160         case Type::dehomogenization:
161         case Type::lattice:
162         case Type::normalization:
163         case Type::cone_and_lattice:
164         case Type::offset:
165         case Type::rees_algebra:
166         case Type::lattice_ideal:
167         case Type::signs:
168         case Type::strict_signs:
169         case Type::scale:
170         case Type::strict_inequalities:
171         case Type::projection_coordinates:
172         case Type::hilbert_basis_rec_cone:
173         case Type::open_facets:
174             return false;
175             break;
176         default:
177             return true;
178             break;
179     }
180 }
181 
182 template <typename Integer>
find_input_matrix(const map<InputType,vector<vector<Integer>>> & multi_input_data,const InputType type)183 vector<vector<Integer> > find_input_matrix(const map<InputType, vector<vector<Integer> > >& multi_input_data,
184                                            const InputType type) {
185     typename map<InputType, vector<vector<Integer> > >::const_iterator it;
186     it = multi_input_data.find(type);
187     if (it != multi_input_data.end())
188         return (it->second);
189 
190     vector<vector<Integer> > dummy;
191     return (dummy);
192 }
193 
194 
195 template <typename Integer>
scale_matrix(vector<vector<Integer>> & mat,const vector<Integer> & scale_axes,bool dual)196 void scale_matrix(vector<vector<Integer> >& mat, const vector<Integer>& scale_axes, bool dual) {
197     for (size_t j = 0; j < scale_axes.size(); ++j) {
198         if (scale_axes[j] == 0)
199             continue;
200         for (size_t i = 0; i < mat.size(); ++i) {
201             if (dual)
202                 mat[i][j] /= scale_axes[j];
203             else
204                 mat[i][j] *= scale_axes[j];
205         }
206     }
207 }
208 
209 template <typename Integer>
scale_input(map<InputType,vector<vector<Integer>>> & multi_input_data,const vector<Integer> scale_axes)210 void scale_input(map<InputType, vector<vector<Integer> > >& multi_input_data, const vector<Integer> scale_axes) {
211 
212     vector<Integer> ScaleHelp = scale_axes;
213     ScaleHelp.resize(scale_axes.size()-1);
214 
215     auto it = multi_input_data.begin();
216     for (; it != multi_input_data.end(); ++it) {
217         switch (it->first) {
218             case Type::inhom_inequalities:
219             case Type::inequalities:
220             case Type::inhom_equations:
221             case Type::equations:
222             case Type::inhom_excluded_faces:
223             case Type::excluded_faces:
224             case Type::dehomogenization:
225             case Type::grading:
226                 scale_matrix(it->second, scale_axes, true);  // true = dual space
227                 break;
228             case Type::polytope:
229                 scale_matrix(it->second, ScaleHelp, false);
230                 break;
231             case Type::cone:
232             case Type::subspace:
233             case Type::lattice:
234             case Type::saturation:
235             case Type::vertices:
236             case Type::offset:
237                 scale_matrix(it->second, scale_axes, false);  // false = primal space
238                 break;
239             default:
240                 break;
241         }
242     }
243 }
244 
245 template <typename Integer>
apply_cale(map<InputType,vector<vector<Integer>>> & multi_input_data)246 void apply_cale(map<InputType, vector<vector<Integer> > >& multi_input_data) {
247     vector<vector<Integer> > scale_mat = find_input_matrix(multi_input_data, Type::scale);
248     vector<Integer> scale_axes = scale_mat[0];
249     scale_input(multi_input_data,scale_axes);
250 }
251 
process_rational_lattice(map<InputType,vector<vector<mpq_class>>> & multi_input_data)252 void process_rational_lattice(map<InputType, vector<vector<mpq_class> > >& multi_input_data){
253 
254     Matrix<mpq_class> RatLat=find_input_matrix(multi_input_data, Type::rational_lattice);
255     Matrix<mpq_class> RatOff = find_input_matrix(multi_input_data, Type::rational_offset);
256 
257     if(RatLat.nr_of_rows() == 0 && RatOff.nr_of_rows() == 0)
258         return;
259 
260     size_t dim;
261     if(RatLat.nr_of_rows() >0 )
262         dim = RatLat.nr_of_columns();
263     else
264         dim = RatOff.nr_of_columns();
265 
266     vector<mpq_class> Den(dim,1);
267     for(size_t i=0; i< RatLat.nr_of_rows(); ++i){
268         for(size_t j=0; j<dim;++j){
269                 Den[j] = libnormaliz::lcm(Den[j].get_num(),RatLat[i][j].get_den());
270         }
271     }
272     if(RatOff.nr_of_rows() > 0){
273         for(size_t j=0; j<dim;++j){
274                 Den[j] = libnormaliz::lcm(Den[j].get_num(),RatOff[0][j].get_den());
275         }
276     }
277 
278     multi_input_data.erase(Type::rational_lattice);
279     multi_input_data.erase(Type::rational_offset);
280     auto it = multi_input_data.begin();
281     for (; it != multi_input_data.end(); ++it) {
282         if(!renf_allowed(it->first))
283             throw BadInputException("Some input type not allowed together with rational_lattice or offset");
284     }
285 
286     if(RatLat.nr_of_rows() > 0)
287         multi_input_data[Type::lattice] = RatLat.get_elements();
288     if(RatOff.nr_of_rows()>0)
289         multi_input_data[Type::offset] = RatOff.get_elements();
290     scale_input(multi_input_data, Den);
291 
292    if(contains(multi_input_data, Type::scale))
293         throw BadInputException("Explicit input type scale only allowed for field coefficients");
294     vector<vector<mpq_class> > DenMat;
295     DenMat.push_back(Den);
296     multi_input_data[Type::scale] = DenMat;  // we use scale to ship Den
297 }
298 
299 template <typename Integer>
mpqclass_input_to_integer(const map<InputType,vector<vector<mpq_class>>> & multi_input_data_const)300 map<InputType, vector<vector<Integer> > > Cone<Integer>::mpqclass_input_to_integer(
301     const map<InputType, vector<vector<mpq_class> > >& multi_input_data_const) {
302 
303     /* cout << "---------------" << endl;
304     for(auto& jt: multi_input_data_const){
305             cout << jt.second;
306             cout << "---------------" << endl;
307     } */
308 
309     map<InputType, vector<vector<mpq_class> > > multi_input_data(
310         multi_input_data_const);  // since we want to change it internally
311 
312     if(contains(multi_input_data, Type::rational_lattice) || contains(multi_input_data, Type::rational_offset))
313         process_rational_lattice(multi_input_data);
314 
315     // The input type polytope is replaced by cone+grading in this routine.
316     // Nevertheless it appears in the subsequent routines.
317     // But any implications of its appearance must be handled here already.
318     // However, polytope can still be used without conversion to cone via libnormaliz !!!!!
319 
320     // since polytope will be converted to cone, we must do some checks here
321     if (contains(multi_input_data, Type::polytope)) {
322         polytope_in_input = true;
323     }
324     if (contains(multi_input_data, Type::grading) && polytope_in_input) {
325         throw BadInputException("No explicit grading allowed with polytope!");
326     }
327     if (contains(multi_input_data, Type::cone) && polytope_in_input) {
328         throw BadInputException("Illegal combination of cone generator types!");
329     }
330 
331     if (contains(multi_input_data, Type::polytope)) {
332         general_no_grading_denom = true;
333     }
334 
335     map<InputType, vector<vector<Integer> > > multi_input_data_ZZ;
336 
337     // special treatment of polytope. We convert it o cone
338     // and define the grading
339     if (contains(multi_input_data, Type::polytope)) {
340         size_t dim;
341         if (multi_input_data[Type::polytope].size() > 0) {
342             dim = multi_input_data[Type::polytope][0].size() + 1;
343             vector<vector<Integer> > grading;
344             grading.push_back(vector<Integer>(dim));
345             grading[0][dim - 1] = 1;
346             multi_input_data_ZZ[Type::grading] = grading;
347         }
348         multi_input_data[Type::cone] = multi_input_data[Type::polytope];
349         multi_input_data.erase(Type::polytope);
350         for (size_t i = 0; i < multi_input_data[Type::cone].size(); ++i) {
351             multi_input_data[Type::cone][i].resize(dim);
352             multi_input_data[Type::cone][i][dim - 1] = 1;
353         }
354     }
355 
356     // now we clear denominators
357     auto it = multi_input_data.begin();
358     for (; it != multi_input_data.end(); ++it) {
359         for (size_t i = 0; i < it->second.size(); ++i) {
360             mpz_class common_denom = 1;
361             for (auto& j : it->second[i]) {
362                 j.canonicalize();
363                 common_denom = libnormaliz::lcm(common_denom, j.get_den());
364             }
365             if (common_denom > 1 && !denominator_allowed(it->first))
366                 throw BadInputException("Proper fraction not allowed in certain input types");
367             vector<Integer> transfer(it->second[i].size());
368             for (size_t j = 0; j < it->second[i].size(); ++j) {
369                 it->second[i][j] *= common_denom;
370                 convert(transfer[j], it->second[i][j].get_num());
371             }
372             multi_input_data_ZZ[it->first].push_back(transfer);
373         }
374     }
375 
376     return multi_input_data_ZZ;
377 }
378 
379 // adds the signs inequalities given by Signs to Inequalities
380 template <typename Integer>
sign_inequalities(const vector<vector<Integer>> & Signs)381 Matrix<Integer> sign_inequalities(const vector<vector<Integer> >& Signs) {
382     if (Signs.size() != 1) {
383         throw BadInputException("ERROR: Bad signs matrix, has " + toString(Signs.size()) + " rows (should be 1)!");
384     }
385     size_t dim = Signs[0].size();
386     Matrix<Integer> Inequ(0, dim);
387     vector<Integer> ineq(dim, 0);
388     for (size_t i = 0; i < dim; i++) {
389         Integer sign = Signs[0][i];
390         if (sign == 1 || sign == -1) {
391             ineq[i] = sign;
392             Inequ.append(ineq);
393             ineq[i] = 0;
394         }
395         else if (sign != 0) {
396             throw BadInputException("Bad signs matrix, has entry " + toString(sign) + " (should be -1, 1 or 0)!");
397         }
398     }
399     return Inequ;
400 }
401 
402 template <typename Integer>
strict_sign_inequalities(const vector<vector<Integer>> & Signs)403 Matrix<Integer> strict_sign_inequalities(const vector<vector<Integer> >& Signs) {
404     if (Signs.size() != 1) {
405         throw BadInputException("ERROR: Bad signs matrix, has " + toString(Signs.size()) + " rows (should be 1)!");
406     }
407     size_t dim = Signs[0].size();
408     Matrix<Integer> Inequ(0, dim);
409     vector<Integer> ineq(dim, 0);
410     ineq[dim - 1] = -1;
411     for (size_t i = 0; i < dim - 1; i++) {  // last component of strict_signs always 0
412         Integer sign = Signs[0][i];
413         if (sign == 1 || sign == -1) {
414             ineq[i] = sign;
415             Inequ.append(ineq);
416             ineq[i] = 0;
417         }
418         else if (sign != 0) {
419             throw BadInputException("Bad signs matrix, has entry " + toString(sign) + " (should be -1, 1 or 0)!");
420         }
421     }
422     return Inequ;
423 }
424 
425 template <typename Integer>
insert_column(vector<vector<Integer>> & mat,size_t col,Integer entry)426 void insert_column(vector<vector<Integer> >& mat, size_t col, Integer entry) {
427     if (mat.size() == 0)
428         return;
429     vector<Integer> help(mat[0].size() + 1);
430     for (size_t i = 0; i < mat.size(); ++i) {
431         for (size_t j = 0; j < col; ++j)
432             help[j] = mat[i][j];
433         help[col] = entry;
434         for (size_t j = col; j < mat[i].size(); ++j)
435             help[j + 1] = mat[i][j];
436         mat[i] = help;
437     }
438 }
439 
440 template <typename Integer>
insert_zero_column(vector<vector<Integer>> & mat,size_t col)441 void insert_zero_column(vector<vector<Integer> >& mat, size_t col) {
442     // Integer entry=0;
443     insert_column<Integer>(mat, col, 0);
444 }
445 
446 template <typename Integer>
447 template <typename InputNumber>
homogenize_input(map<InputType,vector<vector<InputNumber>>> & multi_input_data)448 void Cone<Integer>::homogenize_input(map<InputType, vector<vector<InputNumber> > >& multi_input_data) {
449     auto it = multi_input_data.begin();
450     for (; it != multi_input_data.end(); ++it) {
451         switch (it->first) {
452             case Type::dehomogenization:
453             case Type::support_hyperplanes:
454             case Type::extreme_rays:
455                 throw BadInputException("Types dehomogenization, extreme_rays, support_hyperplanes not allowed with inhomogeneous input!");
456                 break;
457             case Type::inhom_inequalities:  // nothing to do
458             case Type::inhom_equations:
459             case Type::inhom_congruences:
460             case Type::inhom_excluded_faces:
461             case Type::polyhedron:
462             case Type::vertices:
463             case Type::open_facets:
464             case Type::hilbert_basis_rec_cone:
465             case Type::grading:  // already taken care of
466                 break;
467             case Type::strict_inequalities:
468                 insert_column<InputNumber>(it->second, dim - 1, -1);
469                 break;
470             case Type::offset:
471             case Type::projection_coordinates:
472                 insert_column<InputNumber>(it->second, dim - 1, 1);
473                 break;
474             default:  // is correct for signs and strict_signs !
475                 insert_zero_column<InputNumber>(it->second, dim - 1);
476                 break;
477         }
478     }
479 }
480 
481 //---------------------------------------------------------------------------
482 
483 template <typename Integer>
modifyCone(const map<InputType,vector<vector<Integer>>> & multi_add_input_const)484 void Cone<Integer>::modifyCone(const map<InputType, vector<vector<Integer> > >& multi_add_input_const) {
485 
486     if(rational_lattice_in_input)
487         throw BadInputException("Modification of cone not possible with rational_lattice in construction");
488 
489     precomputed_extreme_rays=false;
490     precomputed_support_hyperplanes=false;
491     map<InputType, vector<vector<Integer> > > multi_add_input(multi_add_input_const);
492     check_add_input(multi_add_input);
493     if (inhomogeneous)
494         homogenize_input(multi_add_input);
495 
496     auto T = multi_add_input.begin()->first;
497     if (T == InputType::inequalities || T == InputType::inhom_inequalities || T == InputType::equations ||
498         T == InputType::inhom_equations)
499         AddInequalities.append(Matrix<Integer>(multi_add_input.begin()->second));
500     if (T == InputType::equations || T == InputType::inhom_equations) {
501         Matrix<Integer> Help(multi_add_input.begin()->second);
502         Integer MinusOne = -1;
503         Help.scalar_multiplication(MinusOne);
504         AddInequalities.append(Help);
505     }
506     if (T == InputType::vertices || T == InputType::cone || T == InputType::subspace)
507         AddGenerators.append(Matrix<Integer>(multi_add_input.begin()->second));
508     if (T == InputType::subspace) {
509         Matrix<Integer> Help(multi_add_input.begin()->second);
510         Integer MinusOne = -1;
511         Help.scalar_multiplication(MinusOne);
512         AddGenerators.append(Help);
513     }
514 
515     if (AddInequalities.nr_of_rows() == 0 && AddGenerators.nr_of_rows() == 0)
516         return;
517 
518     if(AddInequalities.nr_of_rows() > 0)
519         addition_generators_allowed = false;
520     if(AddGenerators.nr_of_rows() >0)
521         addition_constraints_allowed = false;
522 
523     if( (AddInequalities.nr_of_rows() > 0 && !addition_constraints_allowed)
524         || (AddGenerators.nr_of_rows() >0 && !addition_generators_allowed) )
525         throw BadInputException("Illgeal modifictaion of cone!");
526 
527     bool save_dehom = isComputed(ConeProperty::Dehomogenization);
528 
529     if (AddGenerators.nr_of_rows() > 0) {
530         if (inhomogeneous)
531             Generators = ExtremeRays;
532         Generators.append(AddGenerators);
533         bool dummy;
534         SupportHyperplanes.resize(0, dim);
535         if (!check_lattice_restrictions_on_generators(dummy))
536             throw BadInputException("Additional generators violate equations of sublattice");
537         if (inhomogeneous)
538             checkDehomogenization();
539         if (Grading.size() > 0) {  // disable grading if it has nonpositive value somewhere
540             for (size_t i = 0; i < Generators.nr_of_rows(); ++i) {
541                 if (v_scalar_product(Grading, Generators[i]) <= 0) {
542                     Grading.resize(0);
543                     break;
544                 }
545             }
546         }
547         delete_aux_cones();
548         is_Computed = ConeProperties();
549         setComputed(ConeProperty::Generators);
550         if (Grading.size() > 0)
551             setComputed(ConeProperty::Grading);
552     }
553 
554     if (AddInequalities.nr_of_rows() > 0) {
555         if(!AddInequalities.zero_product_with_transpose_of(BasisMaxSubspace))
556             throw BadInputException("Additional inequalities do not vanish on maximal subspace");
557         SupportHyperplanes.append(AddInequalities);
558         is_Computed = ConeProperties();
559         setComputed(ConeProperty::MaximalSubspace);  // cannot change since inequalities vanish on max subspace
560         setComputed(ConeProperty::IsPointed);
561     }
562 
563     setComputed(ConeProperty::Dehomogenization, save_dehom);
564 }
565 
566 //---------------------------------------------------------------------------
567 
568 template <typename Integer>
modifyCone(const map<InputType,vector<vector<mpq_class>>> & multi_add_input_const)569 void Cone<Integer>::modifyCone(const map<InputType, vector<vector<mpq_class> > >& multi_add_input_const) {
570     map<InputType, vector<vector<Integer> > > multi_add_input_ZZ = mpqclass_input_to_integer(multi_add_input_const);
571     modifyCone(multi_add_input_ZZ);
572 }
573 
574 //---------------------------------------------------------------------------
575 
576 template <typename Integer>
modifyCone(const map<InputType,vector<vector<nmz_float>>> & multi_add_input_const)577 void Cone<Integer>::modifyCone(const map<InputType, vector<vector<nmz_float> > >& multi_add_input_const) {
578     map<InputType, vector<vector<mpq_class> > > multi_add_input_QQ = nmzfloat_input_to_mpqclass(multi_add_input_const);
579     modifyCone(multi_add_input_QQ);
580 }
581 
582 //---------------------------------------------------------------------------
583 
584 //---------------------------------------------------------------------------
585 
586 template <typename Integer>
delete_aux_cones()587 void Cone<Integer>::delete_aux_cones(){
588     if (IntHullCone != NULL)
589         delete IntHullCone;
590     if (SymmCone != NULL)
591         delete SymmCone;
592     if (ProjCone != NULL)
593         delete ProjCone;
594 }
595 
596 template <typename Integer>
~Cone()597 Cone<Integer>::~Cone() {
598     delete_aux_cones();
599 }
600 
601 //---------------------------------------------------------------------------
602 
603 template <typename Integer>
process_multi_input(const map<InputType,vector<vector<mpq_class>>> & multi_input_data_const)604 void Cone<Integer>::process_multi_input(const map<InputType, vector<vector<mpq_class> > >& multi_input_data_const) {
605     initialize();
606     map<InputType, vector<vector<Integer> > > multi_input_data_ZZ = mpqclass_input_to_integer(multi_input_data_const);
607     process_multi_input_inner(multi_input_data_ZZ);
608 }
609 
610 template <typename Integer>
process_multi_input(const map<InputType,vector<vector<nmz_float>>> & multi_input_data)611 void Cone<Integer>::process_multi_input(const map<InputType, vector<vector<nmz_float> > >& multi_input_data) {
612     initialize();
613     map<InputType, vector<vector<mpq_class> > > multi_input_data_QQ = nmzfloat_input_to_mpqclass(multi_input_data);
614     process_multi_input(multi_input_data_QQ);
615 }
616 
617 template <typename Integer>
check_types_precomputed(map<InputType,vector<vector<Integer>>> & multi_input_data)618 void check_types_precomputed(map<InputType, vector<vector<Integer> > >& multi_input_data) {
619 
620     auto it = multi_input_data.begin();
621     for (; it != multi_input_data.end(); ++it) {
622         switch (it->first) {
623 
624             case Type::maximal_subspace:
625             case Type::generated_lattice:
626             case Type::dehomogenization:
627             case Type::extreme_rays:
628             case Type::support_hyperplanes:
629             case Type::grading:
630                 break;
631             default:
632                 throw BadInputException("Input type not allowed with precomputed data");
633                 break;
634         }
635     }
636 }
637 
638 template <typename Integer>
process_multi_input(const map<InputType,vector<vector<Integer>>> & multi_input_data_const)639 void Cone<Integer>::process_multi_input(const map<InputType, vector<vector<Integer> > >& multi_input_data_const) {
640     initialize();
641     map<InputType, vector<vector<Integer> > > multi_input_data(multi_input_data_const);
642     if (contains(multi_input_data, Type::scale)) {
643         if (using_renf<Integer>()){
644             apply_cale(multi_input_data);
645         }
646         else
647             throw BadInputException("Explicit nput type scale only allowed for field coefficients");
648     }
649     process_multi_input_inner(multi_input_data);
650 }
651 
652 template <typename Integer>
process_multi_input_inner(map<InputType,vector<vector<Integer>>> & multi_input_data)653 void Cone<Integer>::process_multi_input_inner(map<InputType, vector<vector<Integer> > >& multi_input_data) {
654     // find basic input type
655     lattice_ideal_input = false;
656     nr_latt_gen = 0, nr_cone_gen = 0;
657     inhom_input = false;
658 
659     auto it = multi_input_data.begin();
660     if (using_renf<Integer>()) {
661         for (; it != multi_input_data.end(); ++it) {
662             if(!renf_allowed(it->first))
663                 throw BadInputException("Some onput type not allowed for field coefficients");
664         }
665     }
666 
667     if (!using_renf<Integer>() && contains(multi_input_data, Type::scale)) {
668         AxesScaling = multi_input_data[Type::scale][0]; // only possible with rational_lattice
669         setComputed(ConeProperty::AxesScaling);
670         rational_lattice_in_input = true;
671     }
672 
673     // NEW: Empty matrices have syntactical influence
674     it = multi_input_data.begin();
675     for (; it != multi_input_data.end(); ++it) {
676         switch (it->first) {
677             case Type::inhom_inequalities:
678             case Type::strict_inequalities:
679                 inequalities_in_input = true;
680             case Type::inhom_excluded_faces:
681             case Type::inhom_equations:
682             case Type::inhom_congruences:
683             case Type::strict_signs:
684             case Type::open_facets:
685                 inhom_input = true;
686                 break;
687             case Type::signs:
688             case Type::equations:
689             case Type::congruences:
690             case Type::support_hyperplanes:
691                 break;
692             case Type::inequalities:
693                 inequalities_in_input = true;
694                 break;
695             case Type::lattice_ideal:
696                 lattice_ideal_input = true;
697                 break;
698             case Type::polyhedron:
699                 inhom_input = true;
700                 nr_cone_gen++;
701                 break;
702             case Type::integral_closure:
703             case Type::rees_algebra:
704             case Type::polytope:
705             case Type::cone:
706             case Type::subspace:
707             case Type::extreme_rays:
708                 nr_cone_gen++;
709                 break;
710             case Type::normalization:
711             case Type::cone_and_lattice:
712                 nr_cone_gen++;
713                 nr_latt_gen++;
714                 break;
715             case Type::lattice:
716             case Type::saturation:
717             case Type::rational_lattice:
718                 nr_latt_gen++;
719                 break;
720             case Type::vertices:
721             case Type::offset:
722                 inhom_input = true;
723                 break;
724             default:
725                 break;
726         }
727 
728     }
729 
730     INTERRUPT_COMPUTATION_BY_EXCEPTION
731 
732     bool gen_error = false;
733     if (nr_cone_gen > 2)
734         gen_error = true;
735 
736     precomputed_extreme_rays=contains(multi_input_data,Type::extreme_rays);
737     precomputed_support_hyperplanes = contains(multi_input_data,Type::support_hyperplanes);
738     if(precomputed_extreme_rays != precomputed_support_hyperplanes)
739         throw BadInputException("Precomputwed extreme rays and support hyperplanes can only be used together");
740 
741     if(precomputed_extreme_rays)
742         check_types_precomputed(multi_input_data);
743 
744     if (!precomputed_extreme_rays && nr_cone_gen == 2 &&
745         (!contains(multi_input_data, Type::subspace) ||
746          !((contains(multi_input_data, Type::cone) && !polytope_in_input) || contains(multi_input_data, Type::cone_and_lattice) ||
747            contains(multi_input_data, Type::integral_closure) || contains(multi_input_data, Type::normalization))))
748         gen_error = true;
749 
750     if (gen_error) {
751         throw BadInputException("Illegal combination of cone generator types");
752     }
753 
754     if (nr_latt_gen > 1) {
755         throw BadInputException("Only one matrix of lattice generators allowed!");
756     }
757 
758     if (lattice_ideal_input) {
759         if (multi_input_data.size() > 2 || (multi_input_data.size() == 2 && !contains(multi_input_data, Type::grading))) {
760             throw BadInputException("Only grading allowed with lattice_ideal!");
761         }
762     }
763     if (contains(multi_input_data, Type::open_facets)) {
764         size_t allowed = 0;
765         auto it = multi_input_data.begin();
766         for (; it != multi_input_data.end(); ++it) {
767             switch (it->first) {
768                 case Type::open_facets:
769                 case Type::cone:
770                 case Type::grading:
771                 case Type::vertices:
772                     allowed++;
773                     break;
774                 default:
775                     break;
776             }
777         }
778         if (allowed != multi_input_data.size())
779             throw BadInputException("Illegal combination of input types with open_facets!");
780         if (contains(multi_input_data, Type::vertices)) {
781             if (multi_input_data[Type::vertices].size() > 1)
782                 throw BadInputException("At most one vertex allowed with open_facets!");
783         }
784     }
785 
786     /* if (inhom_input) { // checked in homogenize_input
787         if (contains(multi_input_data, Type::dehomogenization) || contains(multi_input_data, Type::support_hyperplanes) ||
788             contains(multi_input_data, Type::extreme_rays)) {
789             throw BadInputException("Some types not allowed in combination with inhomogeneous input!");
790         }
791     }*/
792 
793     if (!inhom_input) {
794         if (contains(multi_input_data, Type::hilbert_basis_rec_cone))
795             throw BadInputException("Type hilbert_basis_rec_cone only allowed with inhomogeneous input!");
796     }
797 
798     if (inhom_input || contains(multi_input_data, Type::dehomogenization)) {
799         if (contains(multi_input_data, Type::rees_algebra) || contains(multi_input_data, Type::polytope) || polytope_in_input) {
800             throw BadInputException("Types polytope and rees_algebra not allowed with inhomogeneous input or dehomogenization!");
801         }
802         // if (contains(multi_input_data, Type::excluded_faces)) {
803         //    throw BadInputException("Type excluded_faces not allowed with inhomogeneous input or dehomogenization!");
804         // }
805     }
806     /*if(contains(multi_input_data,Type::grading) && contains(multi_input_data,Type::polytope)){ // now superfluous
807            throw BadInputException("No explicit grading allowed with polytope!");
808     }*/
809 
810     INTERRUPT_COMPUTATION_BY_EXCEPTION
811 
812     // remove empty matrices
813     it = multi_input_data.begin();
814     for (; it != multi_input_data.end();) {
815         if (it->second.size() == 0)
816             multi_input_data.erase(it++);
817         else
818             ++it;
819     }
820 
821     if (multi_input_data.size() == 0) {
822         throw BadInputException("All input matrices empty!");
823     }
824 
825     // determine dimension
826     it = multi_input_data.begin();
827     size_t inhom_corr = 0;  // correction in the inhom_input case
828     if (inhom_input)
829         inhom_corr = 1;
830     if( it->second.front().size() == 0)
831         throw BadInputException("Ambient space of dimension 0 not allowed");
832     dim = it->second.front().size() - type_nr_columns_correction(it->first) + inhom_corr;
833 
834     // We now process input types that are independent of generators, constraints, lattice_ideal
835     // check for excluded faces
836 
837     ExcludedFaces = find_input_matrix(multi_input_data, Type::excluded_faces);
838     if (ExcludedFaces.nr_of_rows() == 0)
839         ExcludedFaces = Matrix<Integer>(0, dim);  // we may need the correct number of columns
840     Matrix<Integer> InhomExcludedFaces = find_input_matrix(multi_input_data, Type::inhom_excluded_faces);
841     if(InhomExcludedFaces.nr_of_rows() !=0)
842         ExcludedFaces.append(InhomExcludedFaces);
843 
844     // check for a grading
845     vector<vector<Integer> > lf = find_input_matrix(multi_input_data, Type::grading);
846     if (lf.size() > 1) {
847         throw BadInputException("Bad grading, has " + toString(lf.size()) + " rows (should be 1)!");
848     }
849     if (lf.size() == 1) {
850         if (inhom_input)
851             lf[0].push_back(0);  // first we extend grading trivially to have the right dimension
852         setGrading(lf[0]);       // will eventually be set in full_cone.cpp
853     }
854 
855     INTERRUPT_COMPUTATION_BY_EXCEPTION
856 
857     // cout << "Dim " << dim <<endl;
858 
859     check_consistency_of_dimension(multi_input_data);
860 
861     check_length_of_vectors_in_input(multi_input_data,dim-inhom_corr);
862 
863     if (inhom_input)
864         homogenize_input(multi_input_data);
865 
866     // check for codim_bound
867     /*lf = find_input_matrix(multi_input_data,Type::codim_bound_vectors);
868     if (lf.size() > 0) {
869         autom_codim_vectors=convertToLong(lf[0][0]);
870         autom_codim_vectors_set=true;
871     }
872     lf = find_input_matrix(multi_input_data,Type::codim_bound_mult);
873     if (lf.size() > 0) {
874         autom_codim_mult=convertToLong(lf[0][0]);
875         autom_codim_mult_set=true;
876     }*/
877 
878     if (contains(multi_input_data, Type::projection_coordinates)) {
879         projection_coord_indicator.resize(dim);
880         for (size_t i = 0; i < dim; ++i)
881             if (multi_input_data[Type::projection_coordinates][0][i] != 0)
882                 projection_coord_indicator[i] = true;
883     }
884 
885     // check for dehomogenization
886     lf = find_input_matrix(multi_input_data, Type::dehomogenization);
887     if (lf.size() > 1) {
888         throw BadInputException("Bad dehomogenization, has " + toString(lf.size()) + " rows (should be 1)!");
889     }
890     if (lf.size() == 1) {
891         setDehomogenization(lf[0]);
892     }
893 
894     INTERRUPT_COMPUTATION_BY_EXCEPTION
895 
896     // now we can unify implicit and explicit truncation
897     // Note: implicit and explicit truncation have already been excluded
898     if (inhom_input) {
899         Dehomogenization.resize(dim, 0), Dehomogenization[dim - 1] = 1;
900         setComputed(ConeProperty::Dehomogenization);
901     }
902     if (isComputed(ConeProperty::Dehomogenization))
903         inhomogeneous = true;
904 
905     if (lattice_ideal_input) {
906         prepare_input_lattice_ideal(multi_input_data);
907     }
908 
909     INTERRUPT_COMPUTATION_BY_EXCEPTION
910 
911     Matrix<Integer> LatticeGenerators(0, dim);
912     prepare_input_generators(multi_input_data, LatticeGenerators);
913 
914     INTERRUPT_COMPUTATION_BY_EXCEPTION
915 
916     if(!precomputed_extreme_rays)
917         prepare_input_constraints(multi_input_data);  // sets Equations,Congruences,Inequalities
918 
919     INTERRUPT_COMPUTATION_BY_EXCEPTION
920 
921     // set default values if necessary
922     if (inhom_input && LatticeGenerators.nr_of_rows() != 0 && !contains(multi_input_data, Type::offset)) {
923         vector<Integer> offset(dim);
924         offset[dim - 1] = 1;
925         LatticeGenerators.append(offset);
926     }
927     if (inhom_input && Generators.nr_of_rows() != 0 && !contains(multi_input_data, Type::vertices) &&
928         !contains(multi_input_data, Type::polyhedron)) {
929         vector<Integer> vertex(dim);
930         vertex[dim - 1] = 1;
931         Generators.append(vertex);
932     }
933 
934     if(Generators.nr_of_rows() >0 && LatticeGenerators.nr_of_rows()>0 &&
935             !(contains(multi_input_data, Type::cone_and_lattice) || contains(multi_input_data, Type::normalization)))
936         convert_lattice_generators_to_constraints(LatticeGenerators); // necessary in order that we can perform the intersection
937                                                      // of the cone with the subspce generated by LatticeGenerators
938     // cout << "Ineq " << Inequalities.nr_of_rows() << endl;
939 
940     if(precomputed_extreme_rays)
941             LatticeGenerators = find_input_matrix(multi_input_data,Type::generated_lattice);
942 
943     process_lattice_data(LatticeGenerators, Congruences, Equations);
944 
945     // At this point BasisChange has absorbed all input of inequalities coming from cone,
946     // the sublatticd defined by lattice generators,
947     // the sublattice defined by constraints
948     //
949     // Inequalities can be restricted to this sublattice. They may later
950     // restrict the sublattice further.
951     //
952     // BUT: cone generators are not necessarily contained in it.
953     // If they violate equations, we convert the equations to inequalities
954     // If they only violate congruences, we can pass to multiples.
955 
956     remove_superfluous_equations(); // equations satisfied by all cone generators if any
957 
958      //if(Generators.nr_of_rows() >0 && Equations.nr_of_rows() > 0)
959       //   convert_equations_to_inequalties(); // allows us to intersect the cone(Generators) with the subspace(Equations)
960 
961     remove_superfluous_inequalities(); // namely those satisfied by the cone generators if there are any
962 
963     remove_superfluous_congruences(); // ditto
964 
965     INTERRUPT_COMPUTATION_BY_EXCEPTION
966 
967     bool cone_sat_eq = true;
968     bool cone_sat_cong = true;
969     bool cone_sat_ineq = true;
970     if(Generators.nr_of_rows() > 0){
971         cone_sat_eq = (Equations.nr_of_rows()==0);
972         cone_sat_cong = (Congruences.nr_of_rows()==0);
973         cone_sat_ineq = (Inequalities.nr_of_rows()==0);
974     }
975 
976     // cout << "Cond " << cone_sat_eq << cone_sat_ineq << cone_sat_cong << endl;
977 
978     if(precomputed_extreme_rays && !(cone_sat_eq && cone_sat_ineq && cone_sat_cong))
979         throw BadInputException("Precomputed extreme rays violate constraints");
980 
981     if(precomputed_support_hyperplanes && !cone_sat_ineq)
982         throw BadInputException("Precomputed support hyperplanes do not support the cone");
983 
984     // Note: in the inhomogeneous case the original monoid generators as set hetre contain
985     // the verices. So the name is mathematically incorrect, but the different types will be separated
986     // in Full_Cone for the computation of generators OVER original monoid.
987     if(cone_sat_eq && cone_sat_cong && cone_sat_ineq && Generators.nr_of_rows()!=0)
988         set_original_monoid_generators(Generators);
989 
990     if(!cone_sat_cong){
991         for (size_t i = 0; i < Generators.nr_of_rows(); ++i)
992             v_scalar_multiplication(Generators[i], BasisChange.getAnnihilator()); // the saled generators satisfy the congruences
993     }
994 
995     INTERRUPT_COMPUTATION_BY_EXCEPTION
996 
997     if (Inequalities.nr_of_rows() != 0 && Generators.nr_of_rows() == 0) {
998         dual_original_generators = true;
999     }
1000 
1001     if (contains(multi_input_data, Type::open_facets)) {
1002         // read manual for the computation that follows
1003         if (!isComputed(ConeProperty::OriginalMonoidGenerators))  // practically impossible, but better to check
1004             throw BadInputException("Error in connection with open_facets");
1005         if (Generators.nr_of_rows() != BasisChange.getRank())
1006             throw BadInputException("Cone for open_facets not simplicial!");
1007         Matrix<Integer> TransformedGen = BasisChange.to_sublattice(Generators);
1008         vector<key_t> key(TransformedGen.nr_of_rows());
1009         for (size_t j = 0; j < TransformedGen.nr_of_rows(); ++j)
1010             key[j] = j;
1011         Matrix<Integer> TransformedSupps;
1012         Integer dummy;
1013         TransformedGen.simplex_data(key, TransformedSupps, dummy, false);
1014         Matrix<Integer> NewSupps = BasisChange.from_sublattice_dual(TransformedSupps);
1015         NewSupps.remove_row(NewSupps.nr_of_rows() - 1);  // must remove the inequality for the homogenizing variable
1016         for (size_t j = 0; j < NewSupps.nr_of_rows(); ++j) {
1017             if (!(multi_input_data[Type::open_facets][0][j] == 0 || multi_input_data[Type::open_facets][0][j] == 1))
1018                 throw BadInputException("Illegal entry in open_facets");
1019             NewSupps[j][dim - 1] -= multi_input_data[Type::open_facets][0][j];
1020         }
1021         NewSupps.append(BasisChange.getEquationsMatrix());
1022         Matrix<Integer> Ker = NewSupps.kernel(false);  // gives the new verterx
1023         // Ker.pretty_print(cout);
1024         assert(Ker.nr_of_rows() == 1);
1025         Generators[Generators.nr_of_rows() - 1] = Ker[0];
1026         InputGenerators[Generators.nr_of_rows() - 1] = Ker[0];
1027     }
1028 
1029     BasisChangePointed = BasisChange;
1030     setWeights();  // make matrix of weights for sorting
1031 
1032     // Next we must convert generators to constraints if we have mixed input
1033     //
1034     bool must_convert = !cone_sat_eq;
1035     if(Inequalities.nr_of_rows() != 0 && Generators.nr_of_rows() != 0)
1036         must_convert = true;
1037     if(must_convert && verbose)
1038         verboseOutput() << "Converting generators to inequalities" << endl;
1039 
1040     bool inequalities_vanish = Inequalities.zero_product_with_transpose_of(BasisMaxSubspace);
1041 
1042     if(must_convert && cone_sat_eq && inequalities_vanish){ // in this case we can use the already
1043         // computed coordinate transformation and ModifyCone
1044         Cone<Integer> RestoreIfNecessary(*this);
1045         keep_convex_hull_data = true;
1046         setComputed(ConeProperty::Generators);
1047         compute(ConeProperty::SupportHyperplanes);
1048         if(Inequalities.zero_product_with_transpose_of(BasisMaxSubspace)){
1049             if (verbose)
1050                 verboseOutput() << "Conversion finished" << endl;
1051 
1052             if (inhomogeneous) {
1053                 Inequalities.append(Dehomogenization);
1054                 modifyCone(Type::inhom_inequalities, Inequalities);
1055             }
1056             else
1057                 modifyCone(Type::inequalities, Inequalities);
1058             Generators = Matrix<Integer>(0, dim);  // are contained in the ConvexHullData
1059             conversion_done = true;
1060             must_convert = false;
1061             keep_convex_hull_data = false;
1062         }
1063         else
1064             *this = RestoreIfNecessary; // we prefer the method following now.
1065                                        // One could think of a less drastic method
1066     }
1067 
1068     if(must_convert){ // in the remaining case we must use a copy
1069         if (verbose)
1070             verboseOutput() << "Converting generators using a copy" << endl;
1071         Cone<Integer> Copy(Type::cone, Generators);
1072         Copy.compute(ConeProperty::SupportHyperplanes);
1073         Inequalities.append(Copy.getSupportHyperplanesMatrix());
1074         if(Copy.getSublattice().getEquationsMatrix().nr_of_rows()>0){
1075             Inequalities.append(Copy.getSublattice().getEquationsMatrix()); // must convert equations to inequalities
1076             vector<Integer> neg_sum_subspace(dim, 0);
1077             for (size_t i = 0; i < Copy.getSublattice().getEquationsMatrix().nr_of_rows(); ++i)
1078                 neg_sum_subspace = v_add(neg_sum_subspace, Copy.getSublattice().getEquationsMatrix()[i]);
1079             v_scalar_multiplication<Integer>(neg_sum_subspace, -1);
1080             Inequalities.append(neg_sum_subspace);
1081         }
1082         if (verbose)
1083             verboseOutput() << "Conversion finished" << endl;
1084         Generators = Matrix<Integer>(0, dim);
1085         BasisMaxSubspace = Matrix<Integer>(0, dim);
1086     }
1087 
1088     INTERRUPT_COMPUTATION_BY_EXCEPTION
1089 
1090     assert(Inequalities.nr_of_rows() == 0 || Generators.nr_of_rows() == 0);
1091 
1092     if (Generators.nr_of_rows() != 0) {
1093         setComputed(ConeProperty::Generators);
1094         setComputed(ConeProperty::Sublattice);
1095     }
1096 
1097     if (Inequalities.nr_of_rows() != 0 && !conversion_done) {
1098         if (inhomogeneous)
1099             SupportHyperplanes.append(Dehomogenization);  // dehomogenization is first!
1100         SupportHyperplanes.append(Inequalities);
1101         if (inhomogeneous)
1102             Inequalities.append(Dehomogenization);  // needed in check of symmetrization for Ehrhart series
1103     }
1104 
1105     checkGrading(false); // do not compute frading denom
1106     checkDehomogenization();
1107 
1108     if(positive_orthant && Grading.size() > 0){
1109         size_t hom_dim = dim;
1110         if(inhom_input)
1111             hom_dim--;
1112         bool grading_is_positive = true;
1113         for(size_t i=0; i<hom_dim; ++i){
1114             if(Grading[i] <= 0){
1115                 grading_is_positive =  false;
1116                 break;
1117             }
1118         }
1119         if(grading_is_positive){
1120             setComputed(ConeProperty::Grading);
1121             GradingDenom = 1;
1122             setComputed(ConeProperty::GradingDenom);
1123         }
1124     }
1125 
1126     if (!precomputed_extreme_rays && SupportHyperplanes.nr_of_rows() > 0) {
1127         pass_to_pointed_quotient();
1128         check_vanishing_of_grading_and_dehom();
1129     }
1130 
1131 
1132     if (isComputed(ConeProperty::Grading)) {  // cone known to be pointed
1133         setComputed(ConeProperty::MaximalSubspace);
1134         pointed = true;
1135         setComputed(ConeProperty::IsPointed);
1136     }
1137 
1138     // At the end of the construction of the cone we have either
1139     // (1) the cone defined by generators in Generators or
1140     // (2) by inequalities stored in SupportHyperplanes.
1141     // Exceptions: precomputed support hyperplanes (see below) or simultaneous
1142     // input of generators and inequalities (conversion above)
1143     //
1144     // The lattice defining information in the input has been
1145     // processed and sits in BasisChange.
1146     //
1147     // Note that the processing of the inequalities can
1148     // later on change the lattice.
1149     //
1150     // TODO Keep the inequalities in Inequalities,
1151     // and put only the final support hyperplanes into
1152     // SupportHyperplanes.
1153 
1154     // read precomputed data
1155 
1156     INTERRUPT_COMPUTATION_BY_EXCEPTION
1157 
1158     if (precomputed_extreme_rays) {
1159         Generators= find_input_matrix(multi_input_data, Type::extreme_rays);
1160         setComputed(ConeProperty::Generators);
1161         addition_generators_allowed = true;
1162         ExtremeRays.sort_by_weights(WeightsGrad, GradAbs);
1163         set_extreme_rays(vector<bool>(Generators.nr_of_rows(), true));
1164         BasisMaxSubspace=Matrix<Integer>(0,dim);
1165         if(contains(multi_input_data,Type::maximal_subspace))
1166             BasisMaxSubspace=find_input_matrix(multi_input_data,Type::maximal_subspace);
1167         if(BasisMaxSubspace.nr_of_rows()>0){
1168             Matrix<Integer> Help = BasisMaxSubspace; // for protection
1169             Matrix<Integer> Dummy(0,dim);
1170             BasisChangePointed.compose_with_passage_to_quotient(Help,Dummy); // now modulo Help, was not yet pointed
1171         }
1172         pointed = (BasisMaxSubspace.nr_of_rows() == 0);
1173         setComputed(ConeProperty::IsPointed);
1174         setComputed(ConeProperty::MaximalSubspace);
1175         setComputed(ConeProperty::Sublattice);
1176         SupportHyperplanes = find_input_matrix(multi_input_data, Type::support_hyperplanes);
1177         SupportHyperplanes.sort_lex();
1178         setComputed(ConeProperty::SupportHyperplanes);
1179         addition_constraints_allowed=true;
1180 
1181         size_t test_rank=BasisChangePointed.getRank();
1182         if( test_rank != BasisChangePointed.to_sublattice(Generators).rank() ||
1183                 test_rank != BasisChangePointed.to_sublattice_dual(SupportHyperplanes).rank())
1184             throw BadInputException("Precomputed data do not define pointed cone modulo maximal subspace");
1185         create_convex_hull_data();
1186         keep_convex_hull_data=true;
1187     }
1188 
1189     INTERRUPT_COMPUTATION_BY_EXCEPTION
1190 
1191     // for integer hull cones the maximal subsapce is known since it is the same
1192     // as for the original cone
1193     if(is_inthull_cone){
1194         if(contains(multi_input_data, Type::subspace)){
1195             BasisMaxSubspace = find_input_matrix(multi_input_data,Type::subspace);
1196             setComputed(ConeProperty::MaximalSubspace);
1197             if(BasisMaxSubspace.nr_of_rows() > 0){
1198                 Matrix<Integer> Help = BasisMaxSubspace; // for protection
1199                 Matrix<Integer> Dummy(0,dim);
1200                 BasisChangePointed.compose_with_passage_to_quotient(Help,Dummy); // now modulo Help, was not yet pointed
1201             }
1202         }
1203     }
1204 
1205     HilbertBasisRecCone = find_input_matrix(multi_input_data, Type::hilbert_basis_rec_cone);
1206 
1207     INTERRUPT_COMPUTATION_BY_EXCEPTION
1208 
1209     setComputed(ConeProperty::IsInhomogeneous);
1210     setComputed(ConeProperty::EmbeddingDim);
1211 
1212     if (inhomogeneous)
1213         Norm = Dehomogenization;
1214     else
1215         Norm = Grading;
1216 
1217     // standardization for renf>_elem_class
1218 
1219     if (using_renf<Integer>()) {
1220         if (isComputed(ConeProperty::Generators))
1221             Generators.standardize_rows(Norm);
1222         if (isComputed(ConeProperty::Dehomogenization) && isComputed(ConeProperty::Grading))
1223             throw BadInputException("Grading not allowed for inhomogeneous computations over number fields");
1224     }
1225 
1226     AddInequalities.resize(0, dim);
1227     AddGenerators.resize(0, dim);
1228 
1229     /* cout << "Supps " << endl;
1230     SupportHyperplanes.pretty_print(cout);
1231     cout << "Excl " << endl;
1232     ExcludedFaces.pretty_print(cout);
1233     cout << "===========" << endl;
1234     cout << is_Computed << endl;
1235     cout << "===========" << endl; */
1236 
1237     /* if(ExcludedFaces.nr_of_rows()>0){ // Nothing to check anymore
1238         check_excluded_faces();
1239     } */
1240 
1241     /*
1242     cout <<"-----------------------" << endl;
1243     cout << "Gen " << endl;
1244     Generators.pretty_print(cout);
1245     cout << "Supp " << endl;
1246     SupportHyperplanes.pretty_print(cout);
1247     cout << "A" << endl;
1248     BasisChange.get_A().pretty_print(cout);
1249     cout << "B" << endl;
1250     BasisChange.get_B().pretty_print(cout);
1251     cout <<"-----------------------" << endl;
1252     */
1253 }
1254 
1255 //---------------------------------------------------------------------------
1256 template <typename Integer>
remove_superfluous_inequalities()1257 void Cone<Integer>::remove_superfluous_inequalities(){
1258     if (Inequalities.nr_of_rows() > 0 && Generators.nr_of_rows() > 0) {
1259         vector<key_t> essential;
1260         for (size_t i = 0; i < Inequalities.nr_of_rows(); ++i) {
1261             for (size_t j = 0; j < Generators.nr_of_rows(); ++j) {
1262                 if (v_scalar_product(Inequalities[i], Generators[j]) < 0) {
1263                     essential.push_back(i);
1264                     break;
1265                 }
1266             }
1267         }
1268         if (essential.size() < Inequalities.nr_of_rows())
1269             Inequalities = Inequalities.submatrix(essential);
1270     }
1271 }
1272 //---------------------------------------------------------------------------
1273 template <typename Integer>
remove_superfluous_equations()1274 void Cone<Integer>::remove_superfluous_equations(){
1275     if (Equations.nr_of_rows() > 0 && Generators.nr_of_rows() > 0) {
1276         vector<key_t> essential;
1277         for (size_t i = 0; i < Equations.nr_of_rows(); ++i) {
1278             for (size_t j = 0; j < Generators.nr_of_rows(); ++j) {
1279                 if (v_scalar_product(Equations[i], Generators[j]) != 0) {
1280                     essential.push_back(i);
1281                     break;
1282                 }
1283             }
1284         }
1285         if (essential.size() < Equations.nr_of_rows())
1286             Equations = Equations.submatrix(essential);
1287     }
1288 }
1289 
1290 //---------------------------------------------------------------------------
1291 template <typename Integer>
remove_superfluous_congruences()1292 void Cone<Integer>::remove_superfluous_congruences(){
1293     if (Congruences.nr_of_rows() > 0 && Generators.nr_of_rows() > 0) {
1294         vector<key_t> essential;
1295         size_t cc=Congruences[0].size();
1296         for (size_t k = 0; k < Congruences.nr_of_rows(); ++k) {
1297             for(size_t i=0;i< Generators.nr_of_rows(); ++i){
1298                 if (v_scalar_product_vectors_unequal_lungth(Generators[i], Congruences[k]) % Congruences[k][cc - 1] != 0) {  // congruence not satisfied
1299                     essential.push_back(k);
1300                     break;
1301                 }
1302             }
1303         }
1304         if (essential.size() < Congruences.nr_of_rows())
1305             Congruences = Congruences.submatrix(essential);
1306     }
1307 }
1308 
1309 #ifdef ENFNORMALIZ
1310 template <>
remove_superfluous_congruences()1311 void  Cone<renf_elem_class>::remove_superfluous_congruences(){
1312     return;
1313 }
1314 #endif
1315 //---------------------------------------------------------------------------
1316 
1317 // ONLY USED FOR ADDITIONAL GENERATORS
1318 // We check whether the given generators satisfy the lattice restrictions by
1319 // congruences and equations.
1320 // If both are satisfied, we return true.
1321 // If the equations are not satisfied, we return false.
1322 // if only the congruences are violated, the generators are replaced by multiples
1323 // that satisfy the congruences, and return true.
1324 // We need cone_sat_cong to control original generators
1325 template <typename Integer>
check_lattice_restrictions_on_generators(bool & cone_sat_cong)1326 bool Cone<Integer>::check_lattice_restrictions_on_generators(bool& cone_sat_cong) {
1327     if (BasisChange.IsIdentity())
1328         return true;
1329 
1330     for (size_t i = 0; i < Generators.nr_of_rows(); ++i) {
1331         for (size_t j = 0; j < BasisChange.getEquationsMatrix().nr_of_rows(); ++j) {
1332             if (v_scalar_product(Generators[i], BasisChange.getEquationsMatrix()[j]) != 0) {
1333                 return false;
1334             }
1335         }
1336     }
1337 
1338     cone_sat_cong = true;
1339 
1340     if (using_renf<Integer>())  // no congruences to check
1341         return true;
1342 
1343     if (Congruences.nr_of_rows() == 0)
1344         return true;
1345 
1346     for (size_t i = 0; i < Generators.nr_of_rows(); ++i) {
1347         cone_sat_cong = BasisChange.getCongruencesMatrix().check_congruences(Generators[i]);
1348         if (!cone_sat_cong)
1349             break;
1350     }
1351 
1352     if (cone_sat_cong)
1353         return true;
1354 
1355     // multiply generators by anniullator mod sublattice
1356     for (size_t i = 0; i < Generators.nr_of_rows(); ++i)
1357         v_scalar_multiplication(Generators[i], BasisChange.getAnnihilator());
1358 
1359     return true;
1360 }
1361 
1362 //---------------------------------------------------------------------------
1363 
1364 template <typename Integer>
prepare_input_constraints(const map<InputType,vector<vector<Integer>>> & multi_input_data)1365 void Cone<Integer>::prepare_input_constraints(const map<InputType, vector<vector<Integer> > >& multi_input_data) {
1366     Matrix<Integer> Signs(0, dim), StrictSigns(0, dim);
1367 
1368     SupportHyperplanes = Matrix<Integer>(0, dim); // only initialize here
1369 
1370     Inequalities = Matrix<Integer>(0, dim); //these three will be set here
1371     Equations = Matrix<Integer>(0, dim);
1372     Congruences = Matrix<Integer>(0, dim + 1);
1373 
1374     if(precomputed_extreme_rays)
1375         return;
1376 
1377     for (const auto& it : multi_input_data) {
1378         switch (it.first) {
1379             case Type::strict_inequalities:
1380             case Type::inequalities:
1381             case Type::inhom_inequalities:
1382             case Type::excluded_faces:
1383             case Type::inhom_excluded_faces:
1384                 Inequalities.append(it.second);
1385                 break;
1386             case Type::equations:
1387             case Type::inhom_equations:
1388                 Equations.append(it.second);
1389                 break;
1390             case Type::congruences:
1391             case Type::inhom_congruences:
1392                 Congruences.append(it.second);
1393                 break;
1394             case Type::signs:
1395                 Signs = sign_inequalities(it.second);
1396                 break;
1397             case Type::strict_signs:
1398                 StrictSigns = strict_sign_inequalities(it.second);
1399                 break;
1400             default:
1401                 break;
1402         }
1403     }
1404     if (!BC_set)
1405         compose_basis_change(Sublattice_Representation<Integer>(dim));
1406     Matrix<Integer> Help(Signs);  // signs first !!
1407     Help.append(StrictSigns);     // then strict signs
1408     Help.append(Inequalities);
1409     Inequalities = Help;
1410 
1411     insert_default_inequalities(Inequalities);
1412 
1413     vector<Integer> test(dim);
1414     test[dim - 1] = 1;
1415 
1416     if (inhomogeneous && Dehomogenization != test)
1417         return;
1418 
1419     size_t hom_dim = dim;
1420     if (inhomogeneous)
1421         hom_dim--;
1422     positive_orthant = true;
1423     for (size_t i = 0; i < hom_dim; ++i) {
1424         bool found = false;
1425         vector<Integer> gt0(dim);
1426         gt0[i] = 1;
1427         for (size_t j = 0; j < Inequalities.nr_of_rows(); ++j) {
1428             if (Inequalities[j] == gt0) {
1429                 found = true;
1430                 break;
1431             }
1432         }
1433         if (!found) {
1434             positive_orthant = false;
1435             break;
1436         }
1437     }
1438 
1439     if (!positive_orthant)
1440         return;
1441 
1442     Matrix<Integer> HelpEquations(0, dim);
1443 
1444     for (size_t i = 0; i < Equations.nr_of_rows(); ++i) {
1445         if (inhomogeneous && Equations[i][dim - 1] < 0)
1446             continue;
1447         vector<key_t> positive_coord;
1448         for (size_t j = 0; j < hom_dim; ++j) {
1449             if (Equations[i][j] < 0) {
1450                 positive_coord.clear();
1451                 break;
1452             }
1453             if (Equations[i][j] > 0)
1454                 positive_coord.push_back(j);
1455         }
1456         for (unsigned int& k : positive_coord) {
1457             vector<Integer> CoordZero(dim);
1458             CoordZero[k] = 1;
1459             HelpEquations.append(CoordZero);
1460         }
1461     }
1462     Equations.append(HelpEquations);
1463     /* cout << "Help " << HelpEquations.nr_of_rows() <<  endl;
1464     HelpEquations.pretty_print(cout);
1465     cout << "====================================" << endl;
1466     Equations.pretty_print(cout);
1467     cout << "====================================" << endl;*/
1468 }
1469 
1470 //---------------------------------------------------------------------------
1471 template <typename Integer>
prepare_input_generators(map<InputType,vector<vector<Integer>>> & multi_input_data,Matrix<Integer> & LatticeGenerators)1472 void Cone<Integer>::prepare_input_generators(map<InputType, vector<vector<Integer> > >& multi_input_data,
1473                                              Matrix<Integer>& LatticeGenerators) {
1474 
1475     if (contains(multi_input_data, Type::vertices)) {
1476         for (size_t i = 0; i < multi_input_data[Type::vertices].size(); ++i)
1477             if (multi_input_data[Type::vertices][i][dim - 1] <= 0) {
1478                 throw BadInputException("Vertex has non-positive denominator!");
1479             }
1480     }
1481 
1482     if (contains(multi_input_data, Type::polyhedron)) {
1483         for (size_t i = 0; i < multi_input_data[Type::polyhedron].size(); ++i)
1484             if (multi_input_data[Type::polyhedron][i][dim - 1] < 0) {
1485                 throw BadInputException("Polyhedron vertex has negative denominator!");
1486             }
1487     }
1488 
1489     typename map<InputType, vector<vector<Integer> > >::const_iterator it = multi_input_data.begin();
1490     // find specific generator type -- there is only one, as checked already
1491 
1492     INTERRUPT_COMPUTATION_BY_EXCEPTION
1493 
1494     normalization = false;
1495 
1496     // check for subspace
1497     BasisMaxSubspace = find_input_matrix(multi_input_data, Type::subspace);
1498     if (BasisMaxSubspace.nr_of_rows() == 0)
1499         BasisMaxSubspace = Matrix<Integer>(0, dim);
1500 
1501     vector<Integer> neg_sum_subspace(dim, 0);
1502     for (size_t i = 0; i < BasisMaxSubspace.nr_of_rows(); ++i)
1503         neg_sum_subspace = v_add(neg_sum_subspace, BasisMaxSubspace[i]);
1504     v_scalar_multiplication<Integer>(neg_sum_subspace, -1);
1505 
1506     Generators = Matrix<Integer>(0, dim);
1507     for (; it != multi_input_data.end(); ++it) {
1508         INTERRUPT_COMPUTATION_BY_EXCEPTION
1509 
1510         switch (it->first) {
1511             case Type::normalization:
1512             case Type::cone_and_lattice:
1513                 normalization = true;
1514                 LatticeGenerators.append(it->second);
1515                 if (BasisMaxSubspace.nr_of_rows() > 0)
1516                     LatticeGenerators.append(BasisMaxSubspace);
1517                 Generators.append(it->second);
1518                 break;
1519             case Type::vertices:
1520             case Type::polyhedron:
1521             case Type::cone:
1522             case Type::integral_closure:
1523                 Generators.append(it->second);
1524                 break;
1525             case Type::subspace:
1526                     Generators.append(it->second);
1527                     Generators.append(neg_sum_subspace);
1528                 break;
1529             case Type::polytope:
1530                 Generators.append(prepare_input_type_2(it->second));
1531                 break;
1532             case Type::rees_algebra:
1533                 Generators.append(prepare_input_type_3(it->second));
1534                 break;
1535             case Type::lattice:
1536                 LatticeGenerators.append(it->second);
1537                 break;
1538             case Type::saturation:
1539                 LatticeGenerators.append(it->second);
1540                 LatticeGenerators.saturate();
1541                 break;
1542             case Type::offset:
1543                 if (it->second.size() > 1) {
1544                     throw BadInputException("Only one offset allowed!");
1545                 }
1546                 LatticeGenerators.append(it->second);
1547                 break;
1548             default:
1549                 break;
1550         }
1551     }
1552 }
1553 
1554 //---------------------------------------------------------------------------
1555 template <typename Integer>
convert_lattice_generators_to_constraints(Matrix<Integer> & LatticeGenerators)1556 void Cone<Integer>::convert_lattice_generators_to_constraints(Matrix<Integer>& LatticeGenerators){
1557 
1558     Sublattice_Representation<Integer> GenSublattice(LatticeGenerators, false);
1559     Congruences.append(GenSublattice.getCongruencesMatrix());
1560     Equations.append(GenSublattice.getEquationsMatrix());
1561     LatticeGenerators.resize(0);
1562 }
1563 
1564 //---------------------------------------------------------------------------
1565 
1566 /*
1567 template <typename Integer>
1568 void Cone<Integer>::convert_equations_to_inequalties(){
1569 
1570     assert(Equations.nr_of_rows()>0);
1571 
1572    vector<Integer> neg_sum_subspace(dim, 0);
1573     for (size_t i = 0; i < Equations.nr_of_rows(); ++i)
1574         neg_sum_subspace = v_add(neg_sum_subspace, Equations[i]);
1575     v_scalar_multiplication<Integer>(neg_sum_subspace, -1);
1576 
1577     Inequalities.append(Equations);
1578     Inequalities.append(neg_sum_subspace);
1579     Equations.resize(0);
1580 
1581 }
1582 */
1583 
1584 //---------------------------------------------------------------------------
1585 
1586 template <typename Integer>
process_lattice_data(const Matrix<Integer> & LatticeGenerators,Matrix<Integer> & Congruences,Matrix<Integer> & Equations)1587 void Cone<Integer>::process_lattice_data(const Matrix<Integer>& LatticeGenerators,
1588                                          Matrix<Integer>& Congruences,
1589                                          Matrix<Integer>& Equations) {
1590     if (!BC_set)
1591         compose_basis_change(Sublattice_Representation<Integer>(dim));
1592 
1593 
1594 
1595     bool no_constraints = (Congruences.nr_of_rows() == 0) && (Equations.nr_of_rows() == 0);
1596     bool only_cone_gen = (Generators.nr_of_rows() != 0) && no_constraints && (LatticeGenerators.nr_of_rows() == 0);
1597 
1598     INTERRUPT_COMPUTATION_BY_EXCEPTION
1599 
1600     if (only_cone_gen) {
1601         Sublattice_Representation<Integer> Basis_Change(Generators, true);
1602         compose_basis_change(Basis_Change);
1603         return;
1604     }
1605 
1606     INTERRUPT_COMPUTATION_BY_EXCEPTION
1607 
1608     if (normalization && no_constraints && !inhomogeneous) {
1609         Sublattice_Representation<Integer> Basis_Change(Generators, false);
1610         compose_basis_change(Basis_Change);
1611         return;
1612     }
1613 
1614     if (Generators.nr_of_rows() != 0) {
1615         Equations.append(Generators.kernel(!using_renf<Integer>()));
1616     }
1617 
1618     if (LatticeGenerators.nr_of_rows() != 0) {
1619         Sublattice_Representation<Integer> GenSublattice(LatticeGenerators, false);
1620         if ((Equations.nr_of_rows() == 0) && (Congruences.nr_of_rows() == 0)) {
1621             compose_basis_change(GenSublattice);
1622             return;
1623         }
1624         Congruences.append(GenSublattice.getCongruencesMatrix());
1625         Equations.append(GenSublattice.getEquationsMatrix());
1626     }
1627 
1628     INTERRUPT_COMPUTATION_BY_EXCEPTION
1629 
1630     if (Congruences.nr_of_rows() > 0) {
1631         bool zero_modulus;
1632         Matrix<Integer> Ker_Basis = Congruences.solve_congruences(zero_modulus);
1633         if (zero_modulus) {
1634             throw BadInputException("Modulus 0 in congruence!");
1635         }
1636         Sublattice_Representation<Integer> Basis_Change(Ker_Basis, false);
1637         compose_basis_change(Basis_Change);
1638     }
1639 
1640     INTERRUPT_COMPUTATION_BY_EXCEPTION
1641 
1642     if (Equations.nr_of_rows() > 0) {
1643         Matrix<Integer> Ker_Basis = BasisChange.to_sublattice_dual(Equations).kernel(!using_renf<Integer>());
1644         Sublattice_Representation<Integer> Basis_Change(Ker_Basis, true);
1645         compose_basis_change(Basis_Change);
1646     }
1647 }
1648 
1649 //---------------------------------------------------------------------------
1650 
1651 template <typename Integer>
insert_default_inequalities(Matrix<Integer> & Inequalities)1652 void Cone<Integer>::insert_default_inequalities(Matrix<Integer>& Inequalities) {
1653     if (Generators.nr_of_rows() == 0 && Inequalities.nr_of_rows() == 0 && !inequalities_in_input) {
1654         if (verbose) {
1655             verboseOutput() << "No inequalities specified in constraint mode, using non-negative orthant." << endl;
1656         }
1657         if (inhomogeneous) {
1658             vector<Integer> test(dim);
1659             test[dim - 1] = 1;
1660             size_t matsize = dim;
1661             if (test == Dehomogenization)  // in this case "last coordinate >= 0" will come in through the dehomogenization
1662                 matsize = dim - 1;         // we don't check for any other coincidence
1663             Inequalities = Matrix<Integer>(matsize, dim);
1664             for (size_t j = 0; j < matsize; ++j)
1665                 Inequalities[j][j] = 1;
1666         }
1667         else
1668             Inequalities = Matrix<Integer>(dim);
1669     }
1670 }
1671 
1672 //---------------------------------------------------------------------------
1673 
1674 /* polytope input */
1675 template <typename Integer>
prepare_input_type_2(const vector<vector<Integer>> & Input)1676 Matrix<Integer> Cone<Integer>::prepare_input_type_2(const vector<vector<Integer> >& Input) {
1677     size_t j;
1678     size_t nr = Input.size();
1679     // append a column of 1
1680     Matrix<Integer> Generators(nr, dim);
1681     for (size_t i = 0; i < nr; i++) {
1682         for (j = 0; j < dim - 1; j++)
1683             Generators[i][j] = Input[i][j];
1684         Generators[i][dim - 1] = 1;
1685     }
1686     // use the added last component as grading
1687     Grading = vector<Integer>(dim, 0);
1688     Grading[dim - 1] = 1;
1689     setComputed(ConeProperty::Grading);
1690     GradingDenom = 1;
1691     setComputed(ConeProperty::GradingDenom);
1692     return Generators;
1693 }
1694 
1695 //---------------------------------------------------------------------------
1696 
1697 /* rees input */
1698 template <typename Integer>
prepare_input_type_3(const vector<vector<Integer>> & InputV)1699 Matrix<Integer> Cone<Integer>::prepare_input_type_3(const vector<vector<Integer> >& InputV) {
1700     Matrix<Integer> Input(InputV);
1701     int i, j, k, nr_rows = Input.nr_of_rows(), nr_columns = Input.nr_of_columns();
1702     // create cone generator matrix
1703     Matrix<Integer> Full_Cone_Generators(nr_rows + nr_columns, nr_columns + 1, 0);
1704     for (i = 0; i < nr_columns; i++) {
1705         Full_Cone_Generators[i][i] = 1;
1706     }
1707     for (i = 0; i < nr_rows; i++) {
1708         Full_Cone_Generators[i + nr_columns][nr_columns] = 1;
1709         for (j = 0; j < nr_columns; j++) {
1710             Full_Cone_Generators[i + nr_columns][j] = Input[i][j];
1711         }
1712     }
1713     // primarity test
1714     vector<bool> Prim_Test(nr_columns, false);
1715     for (i = 0; i < nr_rows; i++) {
1716         k = 0;
1717         size_t v = 0;
1718         for (j = 0; j < nr_columns; j++)
1719             if (Input[i][j] != 0) {
1720                 k++;
1721                 v = j;
1722             }
1723         if (k == 1)
1724             Prim_Test[v] = true;
1725     }
1726     rees_primary = true;
1727     for (i = 0; i < nr_columns; i++)
1728         if (!Prim_Test[i])
1729             rees_primary = false;
1730 
1731     setComputed(ConeProperty::IsReesPrimary);
1732     return Full_Cone_Generators;
1733 }
1734 
1735 #ifdef ENFNORMALIZ
1736 template <>
prepare_input_type_3(const vector<vector<renf_elem_class>> & InputV)1737 Matrix<renf_elem_class> Cone<renf_elem_class>::prepare_input_type_3(const vector<vector<renf_elem_class> >& InputV) {
1738     assert(false);
1739     return {};
1740 }
1741 #endif
1742 
1743 //---------------------------------------------------------------------------
1744 
1745 template <typename Integer>
prepare_input_lattice_ideal(map<InputType,vector<vector<Integer>>> & multi_input_data)1746 void Cone<Integer>::prepare_input_lattice_ideal(map<InputType, vector<vector<Integer> > >& multi_input_data) {
1747     Matrix<Integer> Binomials(find_input_matrix(multi_input_data, Type::lattice_ideal));
1748 
1749     if (Grading.size() > 0) {
1750         // check if binomials are homogeneous
1751         vector<Integer> degrees = Binomials.MxV(Grading);
1752         for (size_t i = 0; i < degrees.size(); ++i) {
1753             if (degrees[i] != 0) {
1754                 throw BadInputException("Grading gives non-zero value " + toString(degrees[i]) + " for binomial " +
1755                                         toString(i + 1) + "!");
1756             }
1757             if (Grading[i] < 0) {
1758                 throw BadInputException("Grading gives negative value " + toString(Grading[i]) + " for generator " +
1759                                         toString(i + 1) + "!");
1760             }
1761         }
1762     }
1763 
1764     INTERRUPT_COMPUTATION_BY_EXCEPTION
1765 
1766     Matrix<Integer> Gens = Binomials.kernel().transpose();
1767     Full_Cone<Integer> FC(Gens);
1768     FC.verbose = verbose;
1769     if (verbose)
1770         verboseOutput() << "Computing a positive embedding..." << endl;
1771 
1772     FC.dualize_cone();
1773     Matrix<Integer> Supp_Hyp = FC.getSupportHyperplanes().sort_lex();
1774     Matrix<Integer> Selected_Supp_Hyp_Trans = (Supp_Hyp.submatrix(Supp_Hyp.max_rank_submatrix_lex())).transpose();
1775     Matrix<Integer> Positive_Embedded_Generators = Gens.multiplication(Selected_Supp_Hyp_Trans);
1776     // GeneratorsOfToricRing = Positive_Embedded_Generators;
1777     // setComputed(ConeProperty::GeneratorsOfToricRing);
1778     dim = Positive_Embedded_Generators.nr_of_columns();
1779     multi_input_data.insert(make_pair(Type::normalization,
1780                                       Positive_Embedded_Generators.get_elements()));  // this is the cone defined by the binomials
1781 
1782     INTERRUPT_COMPUTATION_BY_EXCEPTION
1783 
1784     if (Grading.size() > 0) {
1785         // solve GeneratorsOfToricRing * grading = old_grading
1786         Integer dummyDenom;
1787         // Grading must be set directly since map entry has been processed already
1788         Grading = Positive_Embedded_Generators.solve_rectangular(Grading, dummyDenom);
1789         if (Grading.size() != dim) {
1790             errorOutput() << "Grading could not be transferred!" << endl;
1791             setComputed(ConeProperty::Grading, false);
1792         }
1793     }
1794 }
1795 
1796 #ifdef ENFNORMALIZ
1797 template <>
prepare_input_lattice_ideal(map<InputType,vector<vector<renf_elem_class>>> & multi_input_data)1798 void Cone<renf_elem_class>::prepare_input_lattice_ideal(map<InputType, vector<vector<renf_elem_class> > >& multi_input_data) {
1799     assert(false);
1800 }
1801 #endif
1802 
1803 /* only used by the constructors */
1804 template <typename Integer>
initialize()1805 void Cone<Integer>::initialize() {
1806     BC_set = false;
1807     is_Computed = bitset<ConeProperty::EnumSize>();  // initialized to false
1808     dim = 0;
1809     unit_group_index = 1;
1810     inhomogeneous = false;
1811     input_automorphisms = false;
1812     rees_primary = false;
1813     triangulation_is_nested = false;
1814     triangulation_is_partial = false;
1815     is_approximation = false;
1816     verbose = libnormaliz::verbose;  // take the global default
1817     if (using_GMP<Integer>()) {
1818         change_integer_type = true;
1819     }
1820     else {
1821         change_integer_type = false;
1822     }
1823     autom_codim_vectors = -1;
1824     autom_codim_mult = -1;
1825     IntHullCone = NULL;
1826     SymmCone = NULL;
1827     ProjCone = NULL;
1828 
1829     set_parallelization();
1830     nmz_interrupted = 0;
1831     is_parallelotope = false;
1832     dual_original_generators = false;
1833     general_no_grading_denom = false;
1834     polytope_in_input = false;
1835     inequalities_in_input = false;
1836     rational_lattice_in_input = false;
1837     face_codim_bound = -1;
1838     positive_orthant = false;
1839     decimal_digits= -1;
1840     block_size_hollow_tri = -1;
1841 
1842     keep_convex_hull_data = false;
1843     conversion_done = false;
1844     ConvHullData.is_primal = false;  // to i9nitialize it
1845 
1846     precomputed_extreme_rays=false;
1847     precomputed_support_hyperplanes=false;
1848 
1849     is_inthull_cone = false;
1850 
1851     addition_constraints_allowed = false;
1852     addition_generators_allowed = false;
1853 
1854     renf_degree = 2;  // to give it a value
1855 }
1856 
1857 template <typename Integer>
set_parallelization()1858 void Cone<Integer>::set_parallelization() {
1859     omp_set_max_active_levels(1);
1860 
1861     if (thread_limit < 0)
1862         throw BadInputException("Invalid thread limit");
1863 
1864     if (parallelization_set) {
1865         if (thread_limit != 0)
1866             omp_set_num_threads(thread_limit);
1867     }
1868     else {
1869         if (std::getenv("OMP_NUM_THREADS") == NULL) {
1870             long old = omp_get_max_threads();
1871             if (old > default_thread_limit)
1872                 set_thread_limit(default_thread_limit);
1873             omp_set_num_threads(thread_limit);
1874         }
1875     }
1876 }
1877 
1878 template <typename Number>
setRenf(const renf_class_shared renf)1879 void Cone<Number>::setRenf(const renf_class_shared renf) {
1880 }
1881 
1882 #ifdef ENFNORMALIZ
1883 template <>
setRenf(const renf_class_shared renf)1884 void Cone<renf_elem_class>::setRenf(const renf_class_shared renf) {
1885     Renf = &*renf;
1886     renf_degree = fmpq_poly_degree(renf->renf_t()->nf->pol);
1887     RenfSharedPtr = renf;
1888 }
1889 
1890 #endif
1891 //---------------------------------------------------------------------------
1892 
1893 template <typename Integer>
compose_basis_change(const Sublattice_Representation<Integer> & BC)1894 void Cone<Integer>::compose_basis_change(const Sublattice_Representation<Integer>& BC) {
1895     if (BC_set) {
1896         BasisChange.compose(BC);
1897     }
1898     else {
1899         BasisChange = BC;
1900         BC_set = true;
1901     }
1902 }
1903 
1904 //---------------------------------------------------------------------------
1905 
1906 template <typename Integer>
setVerbose(bool v)1907 bool Cone<Integer>::setVerbose(bool v) {
1908     // we want to return the old value
1909     bool old = verbose;
1910     verbose = v;
1911     return old;
1912 }
1913 //---------------------------------------------------------------------------
1914 
1915 template <typename Integer>
deactivateChangeOfPrecision()1916 void Cone<Integer>::deactivateChangeOfPrecision() {
1917     change_integer_type = false;
1918 }
1919 
1920 //---------------------------------------------------------------------------
1921 
1922 template <typename Integer>
checkGrading(bool compute_grading_denom)1923 void Cone<Integer>::checkGrading(bool compute_grading_denom) {
1924     if (isComputed(ConeProperty::Grading) || Grading.size() == 0) {
1925         GradingDenom = 1;
1926         return;
1927     }
1928 
1929     bool positively_graded = true;
1930     bool nonnegative = true;
1931     size_t neg_index = 0;
1932     Integer neg_value;
1933     if (Generators.nr_of_rows() > 0) {
1934         vector<Integer> degrees = Generators.MxV(Grading);
1935         for (size_t i = 0; i < degrees.size(); ++i) {
1936             if (degrees[i] <= 0 && (!inhomogeneous || v_scalar_product(Generators[i], Dehomogenization) == 0)) {
1937                 // in the inhomogeneous case: test only generators of tail cone
1938                 positively_graded = false;
1939                 ;
1940                 if (degrees[i] < 0) {
1941                     nonnegative = false;
1942                     neg_index = i;
1943                     neg_value = degrees[i];
1944                 }
1945             }
1946         }
1947         if(compute_grading_denom){
1948             if (positively_graded) {
1949                 vector<Integer> test_grading = BasisChangePointed.to_sublattice_dual_no_div(Grading);
1950                 GradingDenom = v_make_prime(test_grading);
1951             }
1952             else
1953                 GradingDenom = 1;
1954         }
1955     }
1956     else {
1957         GradingDenom = 1;
1958     }
1959 
1960     if (isComputed(ConeProperty::Generators)) {
1961         if (!nonnegative) {
1962             throw BadInputException("Grading gives negative value " + toString(neg_value) + " for generator " +
1963                                     toString(neg_index + 1) + "!");
1964         }
1965         if (positively_graded) {
1966             setComputed(ConeProperty::Grading);
1967             setComputed(ConeProperty::GradingDenom);
1968         }
1969     }
1970 }
1971 
1972 //---------------------------------------------------------------------------
1973 
1974 template <typename Integer>
checkDehomogenization()1975 void Cone<Integer>::checkDehomogenization() {
1976     if (Dehomogenization.size() > 0) {
1977         vector<Integer> test = Generators.MxV(Dehomogenization);
1978         for (size_t i = 0; i < test.size(); ++i)
1979             if (test[i] < 0) {
1980                 throw BadInputException("Dehomogenization has has negative value on generator " + toString(Generators[i]));
1981             }
1982     }
1983 }
1984 //---------------------------------------------------------------------------
1985 
1986 template <typename Integer>
setGrading(const vector<Integer> & lf)1987 void Cone<Integer>::setGrading(const vector<Integer>& lf) {
1988     if (isComputed(ConeProperty::Grading) && Grading == lf) {
1989         return;
1990     }
1991 
1992     if (lf.size() != dim) {
1993         throw BadInputException("Grading linear form has wrong dimension " + toString(lf.size()) + " (should be " +
1994                                 toString(dim) + ")");
1995     }
1996 
1997     Grading = lf;
1998     checkGrading(false); // no computation of GradingDenom
1999 }
2000 
2001 //---------------------------------------------------------------------------
2002 
2003 template <typename Integer>
setWeights()2004 void Cone<Integer>::setWeights() {
2005     if (WeightsGrad.nr_of_columns() != dim) {
2006         WeightsGrad = Matrix<Integer>(0, dim);  // weight matrix for ordering
2007     }
2008     if (Grading.size() > 0 && WeightsGrad.nr_of_rows() == 0)
2009         WeightsGrad.append(Grading);
2010     GradAbs = vector<bool>(WeightsGrad.nr_of_rows(), false);
2011 }
2012 //---------------------------------------------------------------------------
2013 
2014 template <typename Integer>
setDehomogenization(const vector<Integer> & lf)2015 void Cone<Integer>::setDehomogenization(const vector<Integer>& lf) {
2016     if (lf.size() != dim) {
2017         throw BadInputException("Dehomogenizing linear form has wrong dimension " + toString(lf.size()) + " (should be " +
2018                                 toString(dim) + ")");
2019     }
2020     Dehomogenization = lf;
2021     setComputed(ConeProperty::Dehomogenization);
2022 }
2023 
2024 //---------------------------------------------------------------------------
2025 
2026 /* check what is computed */
2027 template <typename Integer>
isComputed(ConeProperty::Enum prop) const2028 bool Cone<Integer>::isComputed(ConeProperty::Enum prop) const {
2029     return is_Computed.test(prop);
2030 }
2031 
2032 template <typename Integer>
getIsComputed() const2033 const ConeProperties& Cone<Integer>::getIsComputed() const{
2034     return is_Computed;
2035 }
2036 
2037 template <typename Integer>
setComputed(ConeProperty::Enum prop)2038 void Cone<Integer>::setComputed(ConeProperty::Enum prop) {
2039     is_Computed.set(prop);
2040 }
2041 
2042 template <typename Integer>
setComputed(ConeProperty::Enum prop,bool value)2043 void Cone<Integer>::setComputed(ConeProperty::Enum prop, bool value) {
2044     is_Computed.set(prop, value);
2045 }
2046 
2047 /*
2048 template <typename Integer>
2049 bool Cone<Integer>::isComputed(ConeProperties CheckComputed) const {
2050     return CheckComputed.reset(is_Computed).any();
2051 }
2052 */
2053 
2054 /*
2055 
2056 template <typename Integer>
2057 void Cone<Integer>::resetComputed(ConeProperty::Enum prop) {
2058     is_Computed.reset(prop);
2059 }
2060 */
2061 
2062 /* getter */
2063 
2064 template <typename Integer>
getIntegerHullCone() const2065 Cone<Integer>& Cone<Integer>::getIntegerHullCone() const {
2066     return *IntHullCone;
2067 }
2068 
2069 template <typename Integer>
getProjectCone() const2070 Cone<Integer>& Cone<Integer>::getProjectCone() const {
2071     return *ProjCone;
2072 }
2073 
2074 template <typename Integer>
getSymmetrizedCone() const2075 Cone<Integer>& Cone<Integer>::getSymmetrizedCone() const {
2076     return *SymmCone;
2077 }
2078 
2079 template <typename Integer>
getRank()2080 size_t Cone<Integer>::getRank() {
2081     compute(ConeProperty::Sublattice);
2082     return BasisChange.getRank();
2083 }
2084 
2085 template <typename Integer>
get_rank_internal()2086 size_t Cone<Integer>::get_rank_internal() {  // introduced at a time when "internal"
2087                                              // external calls of compute were distinguished
2088                                              // most likely supefluous now
2089     if (!isComputed(ConeProperty::Sublattice))
2090         compute(ConeProperty::Sublattice);
2091     return BasisChange.getRank();
2092 }
2093 
2094 template <typename Integer>  // computation depends on InputGenerators
getInternalIndex()2095 Integer Cone<Integer>::getInternalIndex() {
2096     compute(ConeProperty::OriginalMonoidGenerators);
2097     return internal_index;
2098 }
2099 
2100 template <typename Integer>
getUnitGroupIndex()2101 Integer Cone<Integer>::getUnitGroupIndex() {
2102     compute(ConeProperty::OriginalMonoidGenerators, ConeProperty::IsIntegrallyClosed);
2103     return unit_group_index;
2104 }
2105 
2106 template <typename Integer>
getRecessionRank()2107 size_t Cone<Integer>::getRecessionRank() {
2108     compute(ConeProperty::RecessionRank);
2109     return recession_rank;
2110 }
2111 
2112 template <typename Integer>
getAffineDim()2113 long Cone<Integer>::getAffineDim() {
2114     compute(ConeProperty::AffineDim);
2115     return affine_dim;
2116 }
2117 
2118 template <typename Integer>
getSublattice()2119 const Sublattice_Representation<Integer>& Cone<Integer>::getSublattice() {
2120     compute(ConeProperty::Sublattice);
2121     return BasisChange;
2122 }
2123 
2124 template <typename Integer>
get_sublattice_internal()2125 const Sublattice_Representation<Integer>& Cone<Integer>::get_sublattice_internal() {
2126     if (!isComputed(ConeProperty::Sublattice))
2127         compute(ConeProperty::Sublattice);
2128     return BasisChange;
2129 }
2130 
2131 template <typename Integer>
getOriginalMonoidGeneratorsMatrix()2132 const Matrix<Integer>& Cone<Integer>::getOriginalMonoidGeneratorsMatrix() {
2133     compute(ConeProperty::OriginalMonoidGenerators);
2134     return InputGenerators;
2135 }
2136 template <typename Integer>
getOriginalMonoidGenerators()2137 const vector<vector<Integer> >& Cone<Integer>::getOriginalMonoidGenerators() {
2138     compute(ConeProperty::OriginalMonoidGenerators);
2139     return InputGenerators.get_elements();
2140 }
2141 template <typename Integer>
getNrOriginalMonoidGenerators()2142 size_t Cone<Integer>::getNrOriginalMonoidGenerators() {
2143     compute(ConeProperty::OriginalMonoidGenerators);
2144     return InputGenerators.nr_of_rows();
2145 }
2146 
2147 template <typename Integer>
getMaximalSubspace()2148 const vector<vector<Integer> >& Cone<Integer>::getMaximalSubspace() {
2149     compute(ConeProperty::MaximalSubspace);
2150     return BasisMaxSubspace.get_elements();
2151 }
2152 template <typename Integer>
getMaximalSubspaceMatrix()2153 const Matrix<Integer>& Cone<Integer>::getMaximalSubspaceMatrix() {
2154     compute(ConeProperty::MaximalSubspace);
2155     return BasisMaxSubspace;
2156 }
2157 template <typename Integer>
getDimMaximalSubspace()2158 size_t Cone<Integer>::getDimMaximalSubspace() {
2159     compute(ConeProperty::MaximalSubspace);
2160     return BasisMaxSubspace.nr_of_rows();
2161 }
2162 
2163 
2164 
2165 template <typename Integer>
getExtremeRaysMatrix()2166 const Matrix<Integer>& Cone<Integer>::getExtremeRaysMatrix() {
2167     compute(ConeProperty::ExtremeRays);
2168     return ExtremeRaysRecCone;
2169 }
2170 template <typename Integer>
getExtremeRays()2171 const vector<vector<Integer> >& Cone<Integer>::getExtremeRays() {
2172     compute(ConeProperty::ExtremeRays);
2173     return ExtremeRaysRecCone.get_elements();
2174 }
2175 template <typename Integer>
getNrExtremeRays()2176 size_t Cone<Integer>::getNrExtremeRays() {
2177     compute(ConeProperty::ExtremeRays);
2178     return ExtremeRaysRecCone.nr_of_rows();
2179 }
2180 
2181 template <typename Integer>
getVerticesFloatMatrix()2182 const Matrix<nmz_float>& Cone<Integer>::getVerticesFloatMatrix() {
2183     compute(ConeProperty::VerticesFloat);
2184     return VerticesFloat;
2185 }
2186 template <typename Integer>
getVerticesFloat()2187 const vector<vector<nmz_float> >& Cone<Integer>::getVerticesFloat() {
2188     compute(ConeProperty::VerticesFloat);
2189     return VerticesFloat.get_elements();
2190 }
2191 template <typename Integer>
getNrVerticesFloat()2192 size_t Cone<Integer>::getNrVerticesFloat() {
2193     compute(ConeProperty::VerticesFloat);
2194     return VerticesFloat.nr_of_rows();
2195 }
2196 
2197 template <typename Integer>
getExtremeRaysFloatMatrix()2198 const Matrix<nmz_float>& Cone<Integer>::getExtremeRaysFloatMatrix() {
2199     compute(ConeProperty::ExtremeRaysFloat);
2200     return ExtremeRaysFloat;
2201 }
2202 template <typename Integer>
getExtremeRaysFloat()2203 const vector<vector<nmz_float> >& Cone<Integer>::getExtremeRaysFloat() {
2204     compute(ConeProperty::ExtremeRaysFloat);
2205     return ExtremeRaysFloat.get_elements();
2206 }
2207 template <typename Integer>
getNrExtremeRaysFloat()2208 size_t Cone<Integer>::getNrExtremeRaysFloat() {
2209     compute(ConeProperty::ExtremeRaysFloat);
2210     return ExtremeRaysFloat.nr_of_rows();
2211 }
2212 
2213 template <typename Integer>
getSuppHypsFloatMatrix()2214 const Matrix<nmz_float>& Cone<Integer>::getSuppHypsFloatMatrix() {
2215     compute(ConeProperty::SuppHypsFloat);
2216     return SuppHypsFloat;
2217 }
2218 template <typename Integer>
getSuppHypsFloat()2219 const vector<vector<nmz_float> >& Cone<Integer>::getSuppHypsFloat() {
2220     compute(ConeProperty::SuppHypsFloat);
2221     return SuppHypsFloat.get_elements();
2222 }
2223 template <typename Integer>
getNrSuppHypsFloat()2224 size_t Cone<Integer>::getNrSuppHypsFloat() {
2225     compute(ConeProperty::SuppHypsFloat);
2226     return SuppHypsFloat.nr_of_rows();
2227 }
2228 
2229 template <typename Integer>
getVerticesOfPolyhedronMatrix()2230 const Matrix<Integer>& Cone<Integer>::getVerticesOfPolyhedronMatrix() {
2231     compute(ConeProperty::VerticesOfPolyhedron);
2232     return VerticesOfPolyhedron;
2233 }
2234 template <typename Integer>
getVerticesOfPolyhedron()2235 const vector<vector<Integer> >& Cone<Integer>::getVerticesOfPolyhedron() {
2236     compute(ConeProperty::VerticesOfPolyhedron);
2237     return VerticesOfPolyhedron.get_elements();
2238 }
2239 template <typename Integer>
getNrVerticesOfPolyhedron()2240 size_t Cone<Integer>::getNrVerticesOfPolyhedron() {
2241     compute(ConeProperty::VerticesOfPolyhedron);
2242     return VerticesOfPolyhedron.nr_of_rows();
2243 }
2244 
2245 template <typename Integer>
getEquationsMatrix()2246 const Matrix<Integer>& Cone<Integer>::getEquationsMatrix() {
2247     compute(ConeProperty::Equations);
2248     return BasisChange.getEquationsMatrix();
2249 }
2250 template <typename Integer>
getEquations()2251 const vector<vector<Integer> >& Cone<Integer>::getEquations() {
2252     compute(ConeProperty::Equations);
2253     return getEquationsMatrix().get_elements();
2254 }
2255 template <typename Integer>
getNrEquations()2256 size_t Cone<Integer>::getNrEquations() {
2257     compute(ConeProperty::Equations);
2258     return getEquationsMatrix().nr_of_rows();
2259 }
2260 
2261 template <typename Integer>
getCongruencesMatrix()2262 const Matrix<Integer>& Cone<Integer>::getCongruencesMatrix() {
2263     compute(ConeProperty::Congruences);
2264     return BasisChange.getCongruencesMatrix();
2265 }
2266 template <typename Integer>
getCongruences()2267 const vector<vector<Integer> >& Cone<Integer>::getCongruences() {
2268     compute(ConeProperty::Congruences);
2269     return getCongruencesMatrix().get_elements();
2270 }
2271 template <typename Integer>
getNrCongruences()2272 size_t Cone<Integer>::getNrCongruences() {
2273     compute(ConeProperty::Congruences);
2274     return getCongruencesMatrix().nr_of_rows();
2275 }
2276 
2277 template <typename Integer>
getSupportHyperplanesMatrix()2278 const Matrix<Integer>& Cone<Integer>::getSupportHyperplanesMatrix() {
2279     compute(ConeProperty::SupportHyperplanes);
2280     return SupportHyperplanes;
2281 }
2282 template <typename Integer>
getSupportHyperplanes()2283 const vector<vector<Integer> >& Cone<Integer>::getSupportHyperplanes() {
2284     compute(ConeProperty::SupportHyperplanes);
2285     return SupportHyperplanes.get_elements();
2286 }
2287 template <typename Integer>
getNrSupportHyperplanes()2288 size_t Cone<Integer>::getNrSupportHyperplanes() {
2289     compute(ConeProperty::SupportHyperplanes);
2290     return SupportHyperplanes.nr_of_rows();
2291 }
2292 
2293 /*
2294 template <typename Integer>
2295 map<InputType, vector<vector<Integer> > > Cone<Integer>::getConstraints() {
2296     compute(ConeProperty::Sublattice, ConeProperty::SupportHyperplanes);
2297     map<InputType, vector<vector<Integer> > > c;
2298     c[Type::inequalities] = SupportHyperplanes.get_elements();
2299     c[Type::equations] = BasisChange.getEquations();
2300     c[Type::congruences] = BasisChange.getCongruences();
2301     return c;
2302 }
2303 */
2304 
2305 template <typename Integer>
getExcludedFacesMatrix()2306 const Matrix<Integer>& Cone<Integer>::getExcludedFacesMatrix() {
2307     compute(ConeProperty::ExcludedFaces);
2308     return ExcludedFaces;
2309 }
2310 template <typename Integer>
getExcludedFaces()2311 const vector<vector<Integer> >& Cone<Integer>::getExcludedFaces() {
2312     compute(ConeProperty::ExcludedFaces);
2313     return ExcludedFaces.get_elements();
2314 }
2315 template <typename Integer>
getNrExcludedFaces()2316 size_t Cone<Integer>::getNrExcludedFaces() {
2317     compute(ConeProperty::ExcludedFaces);
2318     return ExcludedFaces.nr_of_rows();
2319 }
2320 
2321 template <typename Integer>
getBasicTriangulation()2322 const pair<vector<SHORTSIMPLEX<Integer> >, Matrix<Integer> >& Cone<Integer>::getBasicTriangulation() {
2323     if(!isComputed(ConeProperty::BasicTriangulation)) // no triangulation for output computed
2324         compute(ConeProperty::BasicTriangulation); // we compute the basic triangulation if necessarily
2325     return BasicTriangulation;
2326 }
2327 
2328 template <typename Integer>
getTriangulation()2329 const pair<vector<SHORTSIMPLEX<Integer> >, Matrix<Integer> >& Cone<Integer>::getTriangulation() {
2330     if( is_Computed.intersection_with(all_triangulations()).none() )// no triangulation for output computed
2331         compute(ConeProperty::Triangulation); // we compute the basic triangulation
2332     return Triangulation;
2333 }
2334 
2335 template <typename Integer>
getTriangulation(ConeProperty::Enum quality)2336 const pair<vector<SHORTSIMPLEX<Integer> >, Matrix<Integer> >& Cone<Integer>::getTriangulation(ConeProperty::Enum quality) {
2337     if(! all_triangulations().test(quality) ){
2338         throw BadInputException("Illegal parameter in getTriangulation(ConeProperty::Enum quality)");
2339     }
2340     compute(quality);
2341     return Triangulation;
2342 }
2343 
2344 template <typename Integer>
getConeDecomposition()2345 const pair<vector<SHORTSIMPLEX<Integer> >, Matrix<Integer> >& Cone<Integer>::getConeDecomposition() {
2346     compute(ConeProperty::ConeDecomposition);
2347     return getTriangulation();
2348 }
2349 
2350 template <typename Integer>
getInclusionExclusionData()2351 const vector<pair<vector<key_t>, long> >& Cone<Integer>::getInclusionExclusionData() {
2352     compute(ConeProperty::InclusionExclusionData);
2353     return InExData;
2354 }
2355 
2356 template <typename Integer>
compareStDec(const STANLEYDATA<Integer> & A,const STANLEYDATA<Integer> & B)2357 bool compareStDec(const STANLEYDATA<Integer>& A, const STANLEYDATA<Integer>& B) {
2358     return A.key < B.key;
2359 }
2360 
2361 template <typename Integer>
make_StanleyDec_export(const ConeProperties & ToCompute)2362 void Cone<Integer>::make_StanleyDec_export(const ConeProperties& ToCompute) {
2363     if (!ToCompute.test(ConeProperty::StanleyDec) || isComputed(ConeProperty::StanleyDec) )
2364         return;
2365     assert(isComputed(ConeProperty::BasicStanleyDec));
2366     auto SD = BasicStanleyDec.first.begin();
2367     for (; SD != BasicStanleyDec.first.end(); ++SD) {
2368         STANLEYDATA<Integer> NewSt;
2369         NewSt.key = SD->key;
2370         convert(NewSt.offsets, SD->offsets);
2371         sort(NewSt.offsets.access_elements().begin(), NewSt.offsets.access_elements().end());
2372         StanleyDec.first.push_back(NewSt);
2373     }
2374     StanleyDec.first.sort(compareStDec<Integer>);
2375     StanleyDec.second = BasicStanleyDec.second;
2376     setComputed(ConeProperty::StanleyDec);
2377 }
2378 
2379 template <typename Integer>
getStanleyDec()2380 const pair<list<STANLEYDATA<Integer> >, Matrix<Integer> > & Cone<Integer>::getStanleyDec() {
2381     compute(ConeProperty::StanleyDec);
2382     return StanleyDec;
2383 }
2384 
2385 template <typename Integer>
getStanleyDec_mutable()2386 pair<list<STANLEYDATA_int>, Matrix<Integer> >& Cone<Integer>::getStanleyDec_mutable() {
2387     assert(isComputed(ConeProperty::BasicStanleyDec));
2388     return BasicStanleyDec;
2389 }
2390 
2391 template <typename Integer>
getTriangulationSize()2392 size_t Cone<Integer>::getTriangulationSize() {
2393     compute(ConeProperty::TriangulationSize);
2394     return TriangulationSize;
2395 }
2396 
2397 template <typename Integer>
getTriangulationDetSum()2398 Integer Cone<Integer>::getTriangulationDetSum() {
2399     compute(ConeProperty::TriangulationDetSum);
2400     return TriangulationDetSum;
2401 }
2402 
2403 template <typename Integer>
getWitnessNotIntegrallyClosed()2404 vector<Integer> Cone<Integer>::getWitnessNotIntegrallyClosed() {
2405     compute(ConeProperty::WitnessNotIntegrallyClosed);
2406     return WitnessNotIntegrallyClosed;
2407 }
2408 
2409 template <typename Integer>
getGeneratorOfInterior()2410 vector<Integer> Cone<Integer>::getGeneratorOfInterior() {
2411     compute(ConeProperty::GeneratorOfInterior);
2412     return GeneratorOfInterior;
2413 }
2414 
2415 template <typename Integer>
getAxesScaling()2416 vector<Integer> Cone<Integer>::getAxesScaling() {
2417     if(!isComputed(ConeProperty::AxesScaling))
2418         throw NotComputableException("AxesScaling is not a computation goal");
2419     return AxesScaling;
2420 }
2421 
2422 template <typename Integer>
getCoveringFace()2423 vector<Integer> Cone<Integer>::getCoveringFace() {
2424     compute(ConeProperty::CoveringFace);
2425     return CoveringFace;
2426 }
2427 
2428 template <typename Integer>
getHilbertBasisMatrix()2429 const Matrix<Integer>& Cone<Integer>::getHilbertBasisMatrix() {
2430     compute(ConeProperty::HilbertBasis);
2431     return HilbertBasis;
2432 }
2433 template <typename Integer>
getHilbertBasis()2434 const vector<vector<Integer> >& Cone<Integer>::getHilbertBasis() {
2435     compute(ConeProperty::HilbertBasis);
2436     return HilbertBasis.get_elements();
2437 }
2438 template <typename Integer>
getNrHilbertBasis()2439 size_t Cone<Integer>::getNrHilbertBasis() {
2440     compute(ConeProperty::HilbertBasis);
2441     return HilbertBasis.nr_of_rows();
2442 }
2443 
2444 template <typename Integer>
getModuleGeneratorsOverOriginalMonoidMatrix()2445 const Matrix<Integer>& Cone<Integer>::getModuleGeneratorsOverOriginalMonoidMatrix() {
2446     compute(ConeProperty::ModuleGeneratorsOverOriginalMonoid);
2447     return ModuleGeneratorsOverOriginalMonoid;
2448 }
2449 template <typename Integer>
getModuleGeneratorsOverOriginalMonoid()2450 const vector<vector<Integer> >& Cone<Integer>::getModuleGeneratorsOverOriginalMonoid() {
2451     compute(ConeProperty::ModuleGeneratorsOverOriginalMonoid);
2452     return ModuleGeneratorsOverOriginalMonoid.get_elements();
2453 }
2454 template <typename Integer>
getNrModuleGeneratorsOverOriginalMonoid()2455 size_t Cone<Integer>::getNrModuleGeneratorsOverOriginalMonoid() {
2456     compute(ConeProperty::ModuleGeneratorsOverOriginalMonoid);
2457     return ModuleGeneratorsOverOriginalMonoid.nr_of_rows();
2458 }
2459 
2460 template <typename Integer>
getModuleGeneratorsMatrix()2461 const Matrix<Integer>& Cone<Integer>::getModuleGeneratorsMatrix() {
2462     compute(ConeProperty::ModuleGenerators);
2463     return ModuleGenerators;
2464 }
2465 template <typename Integer>
getModuleGenerators()2466 const vector<vector<Integer> >& Cone<Integer>::getModuleGenerators() {
2467     compute(ConeProperty::ModuleGenerators);
2468     return ModuleGenerators.get_elements();
2469 }
2470 template <typename Integer>
getNrModuleGenerators()2471 size_t Cone<Integer>::getNrModuleGenerators() {
2472     compute(ConeProperty::ModuleGenerators);
2473     return ModuleGenerators.nr_of_rows();
2474 }
2475 
2476 template <typename Integer>
getDeg1ElementsMatrix()2477 const Matrix<Integer>& Cone<Integer>::getDeg1ElementsMatrix() {
2478     compute(ConeProperty::Deg1Elements);
2479     return Deg1Elements;
2480 }
2481 template <typename Integer>
getDeg1Elements()2482 const vector<vector<Integer> >& Cone<Integer>::getDeg1Elements() {
2483     compute(ConeProperty::Deg1Elements);
2484     return Deg1Elements.get_elements();
2485 }
2486 template <typename Integer>
getNrDeg1Elements()2487 size_t Cone<Integer>::getNrDeg1Elements() {
2488     compute(ConeProperty::Deg1Elements);
2489     return Deg1Elements.nr_of_rows();
2490 }
2491 
2492 template <typename Integer>
getNumberLatticePoints()2493 size_t Cone<Integer>::getNumberLatticePoints() {
2494     compute(ConeProperty::NumberLatticePoints);
2495     return number_lattice_points;
2496 }
2497 
2498 template <typename Integer>
getLatticePointsMatrix()2499 const Matrix<Integer>& Cone<Integer>::getLatticePointsMatrix() {
2500     compute(ConeProperty::LatticePoints);
2501     if (!inhomogeneous)
2502         return Deg1Elements;
2503     else
2504         return ModuleGenerators;
2505 }
2506 
2507 template <typename Integer>
getLatticePoints()2508 const vector<vector<Integer> >& Cone<Integer>::getLatticePoints() {
2509     compute(ConeProperty::LatticePoints);
2510     return getLatticePointsMatrix().get_elements();
2511 }
2512 template <typename Integer>
getNrLatticePoints()2513 size_t Cone<Integer>::getNrLatticePoints() {
2514     compute(ConeProperty::LatticePoints);
2515     return getLatticePointsMatrix().nr_of_rows();
2516 }
2517 
2518 template <typename Integer>
getHilbertSeries()2519 const HilbertSeries& Cone<Integer>::getHilbertSeries() {
2520     compute(ConeProperty::HilbertSeries);
2521     return HSeries;
2522 }
2523 
2524 template <typename Integer>
getEhrhartSeries()2525 const HilbertSeries& Cone<Integer>::getEhrhartSeries() {
2526     compute(ConeProperty::EhrhartSeries);
2527     if (inhomogeneous)
2528         return EhrSeries;
2529     else
2530         return HSeries;
2531 }
2532 
2533 template <typename Integer>
getGrading()2534 vector<Integer> Cone<Integer>::getGrading() {
2535     compute(ConeProperty::Grading);
2536     return Grading;
2537 }
2538 
2539 template <typename Integer>
getGradingDenom()2540 Integer Cone<Integer>::getGradingDenom() {
2541     compute(ConeProperty::Grading);
2542     return GradingDenom;
2543 }
2544 
2545 template <typename Integer>
getDehomogenization()2546 vector<Integer> Cone<Integer>::getDehomogenization() {
2547     compute(ConeProperty::Dehomogenization);
2548     return Dehomogenization;
2549 }
2550 
2551 template <typename Integer>
getMultiplicity()2552 mpq_class Cone<Integer>::getMultiplicity() {
2553     compute(ConeProperty::Multiplicity);
2554     return multiplicity;
2555 }
2556 
2557 template <typename Integer>
getVolume()2558 mpq_class Cone<Integer>::getVolume() {
2559     compute(ConeProperty::Volume);
2560     return volume;
2561 }
2562 
2563 template <typename Integer>
getRenfVolume()2564 renf_elem_class Cone<Integer>::getRenfVolume() {
2565     throw NotComputableException("For the volume of rational polytopes use getVolume()");
2566 }
2567 
2568 template <typename Integer>
getRenfData()2569 vector<string> Cone<Integer>::getRenfData() {
2570     throw NotComputableException("Renf data only available for Cone<renf_elem_class>");
2571 }
2572 
2573 template <typename Integer>
getRenfData(const renf_class *)2574 vector<string> Cone<Integer>::getRenfData(const renf_class*) {
2575     throw NotComputableException("Renf data only available for Cone<renf_elem_class>");
2576 }
2577 
2578 template <typename Integer>
getRenf()2579 const renf_class* Cone<Integer>::getRenf() {
2580     throw NotComputableException("Renf only available for Cone<renf_elem_class>");
2581 }
2582 
2583 template <typename Integer>
getRenfSharedPtr()2584 renf_class_shared Cone<Integer>::getRenfSharedPtr(){
2585     if(using_renf<Integer>())
2586         throw NotComputableException("RenfSharedPtr only available for Cone<renf_elem_class>");
2587     else
2588         return RenfSharedPtr;
2589 }
2590 
2591 #ifdef ENFNORMALIZ
2592 template <>
getVolume()2593 mpq_class Cone<renf_elem_class>::getVolume() {
2594     throw NotComputableException("For the volume of algebraic polytopes use getRenfVolume()");
2595 }
2596 
2597 template <>
getRenfVolume()2598 renf_elem_class Cone<renf_elem_class>::getRenfVolume() {
2599     compute(ConeProperty::RenfVolume);
2600     return renf_volume;
2601 }
2602 
2603 template<>
getRenfData(const renf_class * renf)2604 vector<string> Cone<renf_elem_class>::getRenfData(const renf_class* renf) {
2605     std::string s = renf->to_string();
2606 
2607     static const char* prefix = "NumberField(";
2608     static const char* split = ", ";
2609     static const char* suffix = ")";
2610 
2611     assert(s.find(prefix) == 0);
2612     assert(s.find(split) > 0);
2613     assert(s.rfind(suffix) == s.size() - strlen(suffix));
2614 
2615     s = s.substr(strlen(prefix), s.length() - strlen(prefix) - strlen(suffix));
2616 
2617     const int at = s.find(", ");
2618 
2619     return vector<string>{
2620       s.substr(0, at),
2621       s.substr(at + strlen(split)),
2622     };
2623 }
2624 
2625 template<>
getRenfData()2626 vector<string> Cone<renf_elem_class>::getRenfData() {
2627     return Cone<renf_elem_class>::getRenfData(Renf);
2628 }
2629 
2630 template<>
getRenf()2631 const renf_class* Cone<renf_elem_class>::getRenf(){
2632     return Renf;
2633 }
2634 
2635 /*template<>
2636 const std::shared_ptr<const renf_class>  getRenfSharedPtr(){
2637     return RenfSharedPtr;
2638 }*/
2639 #endif
2640 
2641 template <typename Integer>
getEuclideanVolume()2642 nmz_float Cone<Integer>::getEuclideanVolume() {
2643     compute(ConeProperty::Volume);
2644     return euclidean_volume;
2645 }
2646 
2647 template <typename Integer>
getVirtualMultiplicity()2648 mpq_class Cone<Integer>::getVirtualMultiplicity() {
2649     if (!isComputed(ConeProperty::VirtualMultiplicity))  // in order not to compute the triangulation
2650         compute(ConeProperty::VirtualMultiplicity);      // which is deleted if not asked for explicitly
2651     return IntData.getVirtualMultiplicity();
2652 }
2653 
2654 template <typename Integer>
getWeightedEhrhartSeries()2655 const pair<HilbertSeries, mpz_class>& Cone<Integer>::getWeightedEhrhartSeries() {
2656     if (!isComputed(ConeProperty::WeightedEhrhartSeries))  // see above
2657         compute(ConeProperty::WeightedEhrhartSeries);
2658     return getIntData().getWeightedEhrhartSeries();
2659 }
2660 
2661 template <typename Integer>
getIntData()2662 IntegrationData& Cone<Integer>::getIntData() {  // cannot be made const
2663     return IntData;
2664 }
2665 
2666 template <typename Integer>
getIntegral()2667 mpq_class Cone<Integer>::getIntegral() {
2668     if (!isComputed(ConeProperty::Integral))  // see above
2669         compute(ConeProperty::Integral);
2670     return IntData.getIntegral();
2671 }
2672 
2673 template <typename Integer>
getEuclideanIntegral()2674 nmz_float Cone<Integer>::getEuclideanIntegral() {
2675     if (!isComputed(ConeProperty::Integral))  // see above
2676         compute(ConeProperty::EuclideanIntegral);
2677     return IntData.getEuclideanIntegral();
2678 }
2679 
2680 template <typename Integer>
isPointed()2681 bool Cone<Integer>::isPointed() {
2682     compute(ConeProperty::IsPointed);
2683     return pointed;
2684 }
2685 
2686 template <typename Integer>
isEmptySemiOpen()2687 bool Cone<Integer>::isEmptySemiOpen() {
2688     compute(ConeProperty::IsEmptySemiOpen);
2689     return empty_semiopen;
2690 }
2691 
2692 template <typename Integer>
isInhomogeneous()2693 bool Cone<Integer>::isInhomogeneous() {
2694     return inhomogeneous;
2695 }
2696 
2697 template <typename Integer>
isIntHullCone()2698 bool Cone<Integer>::isIntHullCone() {
2699     return is_inthull_cone;
2700 }
2701 
2702 template <typename Integer>
isDeg1ExtremeRays()2703 bool Cone<Integer>::isDeg1ExtremeRays() {
2704     compute(ConeProperty::IsDeg1ExtremeRays);
2705     return deg1_extreme_rays;
2706 }
2707 
2708 template <typename Integer>
isGorenstein()2709 bool Cone<Integer>::isGorenstein() {
2710     compute(ConeProperty::IsGorenstein);
2711     return Gorenstein;
2712 }
2713 
2714 template <typename Integer>
isDeg1HilbertBasis()2715 bool Cone<Integer>::isDeg1HilbertBasis() {
2716     compute(ConeProperty::IsDeg1HilbertBasis);
2717     return deg1_hilbert_basis;
2718 }
2719 
2720 template <typename Integer>
isIntegrallyClosed()2721 bool Cone<Integer>::isIntegrallyClosed() {
2722     compute(ConeProperty::IsIntegrallyClosed);
2723     return integrally_closed;
2724 }
2725 
2726 template <typename Integer>
isReesPrimary()2727 bool Cone<Integer>::isReesPrimary() {
2728     compute(ConeProperty::IsReesPrimary);
2729     return rees_primary;
2730 }
2731 
2732 template <typename Integer>
getReesPrimaryMultiplicity()2733 Integer Cone<Integer>::getReesPrimaryMultiplicity() {
2734     compute(ConeProperty::ReesPrimaryMultiplicity);
2735     return ReesPrimaryMultiplicity;
2736 }
2737 
2738 // the information about the triangulation will just be returned
2739 // if no triangulation was computed so far they return false
2740 template <typename Integer>
isTriangulationNested()2741 bool Cone<Integer>::isTriangulationNested() {
2742     if(!isComputed(ConeProperty::IsTriangulationNested))
2743         throw NotComputableException("isTriangulationNested() only defined if a triangulation has been computed");
2744     return triangulation_is_nested;
2745 }
2746 template <typename Integer>
isTriangulationPartial()2747 bool Cone<Integer>::isTriangulationPartial() {
2748     if(!isComputed(ConeProperty::IsTriangulationPartial))
2749         throw NotComputableException("isTriangulationPartial() only defined if a triangulation has been computed");
2750     return triangulation_is_partial;
2751 }
2752 
2753 template <typename Integer>
getModuleRank()2754 size_t Cone<Integer>::getModuleRank() {
2755     compute(ConeProperty::ModuleRank);
2756     return module_rank;
2757 }
2758 
2759 template <typename Integer>
getClassGroup()2760 vector<Integer> Cone<Integer>::getClassGroup() {
2761     compute(ConeProperty::ClassGroup);
2762     return ClassGroup;
2763 }
2764 
2765 template <typename Integer>
getAutomorphismGroup(ConeProperty::Enum quality)2766 const AutomorphismGroup<Integer>& Cone<Integer>::getAutomorphismGroup(ConeProperty::Enum quality) {
2767 
2768     if (!all_automorphisms().test(quality)) {
2769         throw BadInputException("Illegal parameter in getAutomorphismGroup(ConeProperty::Enum quality)");
2770     }
2771     compute(quality);
2772     return Automs;
2773 }
2774 
2775 template <typename Integer>
getAutomorphismGroup()2776 const AutomorphismGroup<Integer>& Cone<Integer>::getAutomorphismGroup() {
2777     if (is_Computed.intersection_with(all_automorphisms()).none() ) {
2778         throw BadInputException("No automorphism group computed. Use getAutomorphismGroup(ConeProperty::Enum quality)");
2779     }
2780 
2781     return Automs;
2782 }
2783 
2784 
2785 
2786 template <typename Integer>
getFaceLattice()2787 const map<dynamic_bitset, int>& Cone<Integer>::getFaceLattice() {
2788     compute(ConeProperty::FaceLattice);
2789     return FaceLat;
2790 }
2791 
2792 template <typename Integer>
getIncidence()2793 const vector<dynamic_bitset>& Cone<Integer>::getIncidence() {
2794     compute(ConeProperty::Incidence);
2795     return SuppHypInd;
2796 }
2797 
2798 template <typename Integer>
getFVector()2799 vector<size_t> Cone<Integer>::getFVector() {
2800     compute(ConeProperty::FVector);
2801     return f_vector;
2802 }
2803 
2804 template <typename Integer>
getDualFaceLattice()2805 const map<dynamic_bitset, int>& Cone<Integer>::getDualFaceLattice() {
2806     compute(ConeProperty::DualFaceLattice);
2807     return DualFaceLat;
2808 }
2809 
2810 template <typename Integer>
getDualIncidence()2811 const vector<dynamic_bitset>& Cone<Integer>::getDualIncidence() {
2812     compute(ConeProperty::DualIncidence);
2813     return DualSuppHypInd;
2814 }
2815 
2816 template <typename Integer>
getDualFVector()2817 vector<size_t> Cone<Integer>::getDualFVector() {
2818     compute(ConeProperty::DualFVector);
2819     return dual_f_vector;
2820 }
2821 
2822 //---------------------------------------------------------------------------
2823 
2824 template <typename Integer>
compute_lattice_points_in_polytope(ConeProperties & ToCompute)2825 void Cone<Integer>::compute_lattice_points_in_polytope(ConeProperties& ToCompute) {
2826     assert(false);
2827 }
2828 
2829 #ifdef ENFNORMALIZ
2830 template <>
project_and_lift(const ConeProperties & ToCompute,Matrix<renf_elem_class> & Deg1,const Matrix<renf_elem_class> & Gens,const Matrix<renf_elem_class> & Supps,const Matrix<renf_elem_class> & Congs,const vector<renf_elem_class> GradingOnPolytope)2831 void Cone<renf_elem_class>::project_and_lift(const ConeProperties& ToCompute,
2832                                              Matrix<renf_elem_class>& Deg1,
2833                                              const Matrix<renf_elem_class>& Gens,
2834                                              const Matrix<renf_elem_class>& Supps,
2835                                              const Matrix<renf_elem_class>& Congs,
2836                                              const vector<renf_elem_class> GradingOnPolytope) {
2837     // if(verbose)
2838     //    verboseOutput() << "Starting projection" << endl;
2839 
2840     // vector<dynamic_bitset> Pair;
2841     //  vector<dynamic_bitset> ParaInPair;
2842 
2843     vector<dynamic_bitset> Ind;
2844     //
2845     // if(!is_parallelotope){
2846     Ind = vector<dynamic_bitset>(Supps.nr_of_rows(), dynamic_bitset(Gens.nr_of_rows()));
2847     for (size_t i = 0; i < Supps.nr_of_rows(); ++i)
2848         for (size_t j = 0; j < Gens.nr_of_rows(); ++j)
2849             if (v_scalar_product(Supps[i], Gens[j]) == 0)
2850                 Ind[i][j] = true;
2851     //}
2852 
2853     size_t rank = BasisChangePointed.getRank();
2854 
2855     Matrix<renf_elem_class> Verts;
2856     if (isComputed(ConeProperty::Generators)) {
2857         vector<key_t> choice = identity_key(Gens.nr_of_rows());  // Gens.max_rank_submatrix_lex();
2858         if (choice.size() >= dim)
2859             Verts = Gens.submatrix(choice);
2860     }
2861 
2862     Matrix<mpz_class> Raw(0, Gens.nr_of_columns());
2863 
2864     vector<renf_elem_class> Dummy;
2865     // project_and_lift_inner<renf_elem_class>(Deg1,Supps,Ind,GradingDenom,rank,verbose,true,Dummy);
2866     ProjectAndLift<renf_elem_class, mpz_class> PL;
2867     // if(!is_parallelotope)
2868     PL = ProjectAndLift<renf_elem_class, mpz_class>(Supps, Ind, rank);
2869     // else
2870     //    PL=ProjectAndLift<renf_elem_class,renf_elem_class>(Supps,Pair,ParaInPair,rank);
2871     PL.set_grading_denom(1);
2872     PL.set_verbose(verbose);
2873     PL.set_no_relax(ToCompute.test(ConeProperty::NoRelax));
2874     PL.set_LLL(false);
2875     PL.set_vertices(Verts);
2876     PL.compute();
2877     PL.put_eg1Points_into(Raw);
2878 
2879     for (size_t i = 0; i < Raw.nr_of_rows(); ++i) {
2880         vector<renf_elem_class> point(dim);
2881         for (size_t j = 0; j < dim; ++j) {
2882             point[j] = Raw[i][j + 1];
2883         }
2884         if (inhomogeneous) {
2885             ModuleGenerators.append(point);
2886         }
2887         else {
2888             Deg1Elements.append(point);
2889         }
2890     }
2891     if (inhomogeneous)
2892         ModuleGenerators.sort_by_weights(WeightsGrad, GradAbs);
2893     else
2894         Deg1Elements.sort_by_weights(WeightsGrad, GradAbs);
2895 
2896     number_lattice_points = PL.getNumberLatticePoints();
2897     setComputed(ConeProperty::NumberLatticePoints);
2898 
2899     if (verbose)
2900         verboseOutput() << "Project-and-lift complete" << endl
2901                         << "------------------------------------------------------------" << endl;
2902 }
2903 
2904 template <>
compute_lattice_points_in_polytope(ConeProperties & ToCompute)2905 void Cone<renf_elem_class>::compute_lattice_points_in_polytope(ConeProperties& ToCompute) {
2906     if (isComputed(ConeProperty::ModuleGenerators) || isComputed(ConeProperty::Deg1Elements))
2907         return;
2908     if (!ToCompute.test(ConeProperty::ModuleGenerators) && !ToCompute.test(ConeProperty::Deg1Elements))
2909         return;
2910 
2911     if (!isComputed(ConeProperty::Grading) && !isComputed(ConeProperty::Dehomogenization))
2912         throw BadInputException("Lattice points not computable without grading in the homogeneous case");
2913 
2914     compute(ConeProperty::SupportHyperplanes);
2915     if (!isComputed(ConeProperty::SupportHyperplanes))
2916         throw FatalException("Could not compute SupportHyperplanes");
2917 
2918     if (inhomogeneous && ExtremeRaysRecCone.nr_of_rows() > 0) {
2919         throw BadInputException("Lattice points not computable for unbounded poyhedra");
2920     }
2921 
2922     // The same procedure as in cone.cpp, but no approximation, and grading always extra first coordinate
2923 
2924     renf_elem_class MinusOne = -1;
2925 
2926     vector<vector<renf_elem_class> > SuppsHelp = SupportHyperplanes.get_elements();
2927     Matrix<renf_elem_class> Equs = BasisChange.getEquationsMatrix();
2928     for (size_t i = 0; i < Equs.nr_of_rows(); ++i) {  // add equations as inequalities
2929         SuppsHelp.push_back(Equs[i]);
2930         SuppsHelp.push_back(Equs[i]);
2931         v_scalar_multiplication(SuppsHelp.back(), MinusOne);
2932     }
2933     renf_elem_class Zero = 0;
2934     insert_column(SuppsHelp, 0, Zero);
2935 
2936     // we insert the degree/level into the 0th column
2937     vector<renf_elem_class> ExtraEqu(1, -1);
2938     for (size_t j = 0; j < dim; ++j) {
2939         if (inhomogeneous)
2940             ExtraEqu.push_back(Dehomogenization[j]);
2941         else
2942             ExtraEqu.push_back(Grading[j]);
2943     }
2944     SuppsHelp.push_back(ExtraEqu);
2945     v_scalar_multiplication(ExtraEqu, MinusOne);
2946     SuppsHelp.push_back(ExtraEqu);
2947 
2948     Matrix<renf_elem_class> Supps(SuppsHelp);
2949 
2950     Matrix<renf_elem_class> Gens;
2951     if (inhomogeneous)
2952         Gens = VerticesOfPolyhedron;
2953     else
2954         Gens = ExtremeRays;
2955 
2956     Matrix<renf_elem_class> GradGen(0, dim + 1);
2957     for (size_t i = 0; i < Gens.nr_of_rows(); ++i) {
2958         vector<renf_elem_class> gg(dim + 1);
2959         for (size_t j = 0; j < dim; ++j)
2960             gg[j + 1] = Gens[i][j];
2961         if (inhomogeneous)
2962             gg[0] = v_scalar_product(Gens[i], Dehomogenization);
2963         else
2964             gg[0] = v_scalar_product(Gens[i], Grading);
2965         GradGen.append(gg);
2966     }
2967 
2968     Deg1Elements.resize(0, dim);
2969     ModuleGenerators.resize(0, dim);
2970     Matrix<renf_elem_class> DummyCongs(0, 0);
2971     Matrix<renf_elem_class> DummyResult(0, 0);
2972     vector<renf_elem_class> dummy_grad(0);
2973 
2974     if (inhomogeneous)
2975         project_and_lift(ToCompute, DummyResult, GradGen, Supps, DummyCongs, dummy_grad);
2976     else
2977         project_and_lift(ToCompute, DummyResult, GradGen, Supps, DummyCongs, dummy_grad);
2978 
2979     // In this version, the lattice points are transferresd into the cone
2980     // in project_and_lift below.
2981 
2982     if (inhomogeneous)
2983         setComputed(ConeProperty::ModuleGenerators);
2984     else
2985         setComputed(ConeProperty::Deg1Elements);
2986 }
2987 #endif
2988 
2989 //---------------------------------------------------------------------------
2990 
2991 
2992 #ifdef ENFNORMALIZ
2993 template <>
prepare_volume_computation(ConeProperties & ToCompute)2994 void Cone<renf_elem_class>::prepare_volume_computation(ConeProperties& ToCompute) {
2995     if (!ToCompute.test(ConeProperty::Volume))
2996         return;
2997 
2998     if (!inhomogeneous && !isComputed(ConeProperty::Grading))
2999         throw NotComputableException("Volume needs a grading in the homogeneous case");
3000     if (getRank() != dim)
3001         throw NotComputableException("Normaliz requires full dimension for volume of algebraic polytope");
3002     vector<renf_elem_class> Grad;
3003     if (inhomogeneous)
3004         Grad = Dehomogenization;
3005     else
3006         Grad = Grading;
3007 
3008     /* for(size_t i=0;i<dim;++i)
3009         if(!Grad[i].is_integer())
3010             throw NotComputableException("Entries of grading or dehomogenization must be mpzegers for volume");*/
3011 
3012     vector<mpz_class> Grad_mpz;
3013     for (size_t i = 0; i < dim; ++i)
3014         Grad_mpz.push_back(Grad[i].num());
3015     for (size_t i = 0; i < dim; ++i) {
3016         if (Grad[i] != Grad_mpz[i])
3017             throw BadInputException("Entries of grading or dehomogenization must be coprime integers for volume");
3018     }
3019     // if(libnormaliz::v_make_prime(Grad_mpz)!=1)
3020     //    throw NotComputableException("Entries of grading or dehomogenization must be coprime integers for volume");
3021 
3022     vector<double> Grad_double(dim);
3023     for (size_t i = 0; i < dim; ++i)
3024         // libnormaliz::convert(Grad_double[i],Grad_mpz[i]);
3025         Grad_double[i] = Grad_mpz[i].get_d();
3026 
3027     double norm = v_scalar_product(Grad_double, Grad_double);
3028     euclidean_height = sqrt(norm);
3029 }
3030 #endif
3031 //---------------------------------------------------------------------------
3032 
3033 template <typename Integer>
compute_full_cone(ConeProperties & ToCompute)3034 void Cone<Integer>::compute_full_cone(ConeProperties& ToCompute) {
3035 
3036     if(ToCompute.test(ConeProperty::PullingTriangulationInternal))
3037         assert(ToCompute.count() == 1);
3038 
3039     if (change_integer_type) {
3040         try {
3041             compute_full_cone_inner<MachineInteger>(ToCompute);
3042         } catch (const ArithmeticException& e) {
3043             if (verbose) {
3044                 verboseOutput() << e.what() << endl;
3045                 verboseOutput() << "Restarting with a bigger type." << endl;
3046             }
3047             change_integer_type = false;
3048         }
3049     }
3050 
3051     if (!change_integer_type) {
3052         if (!using_GMP<Integer>() && !ToCompute.test(ConeProperty::DefaultMode)) {
3053             compute_full_cone_inner<Integer>(ToCompute);
3054         }
3055         else {
3056             try {
3057                 compute_full_cone_inner<Integer>(ToCompute);
3058             } catch (const ArithmeticException& e) {  // the nonly reason for failure is an overflow in a degree computation
3059                 if (verbose) {                        // so we can relax in default mode
3060                     verboseOutput() << e.what() << endl;
3061                     verboseOutput() << "Reducing computation goals." << endl;
3062                 }
3063                 ToCompute.reset(ConeProperty::HilbertBasis);
3064                 ToCompute.reset(ConeProperty::HilbertSeries);
3065                 compute_full_cone_inner<Integer>(ToCompute);
3066             }
3067         }
3068     }
3069 }
3070 
3071 
3072 template <typename Integer>
3073 template <typename IntegerFC>
compute_full_cone_inner(ConeProperties & ToCompute)3074 void Cone<Integer>::compute_full_cone_inner(ConeProperties& ToCompute) {
3075 
3076 #ifdef NMZ_EXTENDED_TESTS
3077     if(!using_GMP<IntegerFC>() && !using_renf<IntegerFC>() && test_arith_overflow_full_cone)
3078         throw ArithmeticException(0);
3079 #endif
3080 
3081     if (ToCompute.test(ConeProperty::IsPointed) && Grading.size() == 0) {
3082         if (verbose) {
3083             verboseOutput() << "Checking pointedness first" << endl;
3084         }
3085         ConeProperties Dualize;
3086         Dualize.set(ConeProperty::SupportHyperplanes);
3087         Dualize.set(ConeProperty::ExtremeRays);
3088         compute(Dualize);
3089     }
3090 
3091     Matrix<IntegerFC> FC_Gens;
3092 
3093     BasisChangePointed.convert_to_sublattice(FC_Gens, Generators);
3094     Full_Cone<IntegerFC> FC(FC_Gens, !(ToCompute.test(ConeProperty::ModuleGeneratorsOverOriginalMonoid) ||
3095             ToCompute.test(ConeProperty::AllGeneratorsTriangulation)));
3096     // !ToCompute.test(ConeProperty::ModuleGeneratorsOverOriginalMonoid) blocks make_prime in full_cone.cpp
3097 
3098     /* activate bools in FC */
3099 
3100     if(ToCompute.test(ConeProperty::IsEmptySemiOpen) && !isComputed(ConeProperty::IsEmptySemiOpen))
3101         FC.check_semiopen_empty = true;
3102 
3103     if(ToCompute.test(ConeProperty::FullConeDynamic)){
3104         FC.do_supphyps_dynamic=true;
3105         if(IntHullNorm.size() > 0)
3106             BasisChangePointed.convert_to_sublattice_dual(FC.IntHullNorm,IntHullNorm);
3107     }
3108 
3109     FC.keep_convex_hull_data = keep_convex_hull_data;
3110 
3111     FC.verbose = verbose;
3112     FC.renf_degree = renf_degree;  // even if it is not defined without renf
3113 
3114     FC.inhomogeneous = inhomogeneous;
3115     // FC.explicit_h_vector=(ToCompute.test(ConeProperty::ExplicitHilbertSeries) && !isComputed(ConeProperty::HilbertSeries));
3116 
3117     if (ToCompute.test(ConeProperty::HilbertSeries)) {
3118         FC.do_h_vector = true;
3119         FC.Hilbert_Series.set_period_bounded(HSeries.get_period_bounded());
3120     }
3121     if (ToCompute.test(ConeProperty::HilbertBasis)) {
3122         FC.do_Hilbert_basis = true;
3123     }
3124     if (ToCompute.test(ConeProperty::ModuleGeneratorsOverOriginalMonoid)) {
3125         FC.do_module_gens_intcl = true;
3126     }
3127 
3128     if (ToCompute.test(ConeProperty::IsIntegrallyClosed) || ToCompute.test(ConeProperty::WitnessNotIntegrallyClosed)) {
3129         FC.do_integrally_closed = true;
3130     }
3131 
3132     if (ToCompute.test(ConeProperty::BasicTriangulation) ) {
3133         FC.keep_triangulation = true;
3134     }
3135 
3136     if (ToCompute.test(ConeProperty::PullingTriangulationInternal) ) {
3137         FC.pulling_triangulation = true;
3138     }
3139 
3140     if (ToCompute.test(ConeProperty::ConeDecomposition)) {
3141         FC.do_cone_dec = true;
3142     }
3143     if (ToCompute.test(ConeProperty::Multiplicity) || (using_renf<Integer>() && ToCompute.test(ConeProperty::Volume))) {
3144         FC.do_multiplicity = true;
3145     }
3146 
3147     if (ToCompute.test(ConeProperty::TriangulationDetSum)) {
3148         FC.do_determinants = true;
3149     }
3150     if (ToCompute.test(ConeProperty::TriangulationSize)) {
3151         FC.do_triangulation_size = true;
3152     }
3153     if (ToCompute.test(ConeProperty::NoSubdivision)) {
3154         FC.use_bottom_points = false;
3155     }
3156     if (ToCompute.test(ConeProperty::Deg1Elements) && !using_renf<Integer>()) {
3157         FC.do_deg1_elements = true;
3158     }
3159     if (ToCompute.test(ConeProperty::BasicStanleyDec)) {
3160         FC.do_Stanley_dec = true;
3161     }
3162 
3163     if (ToCompute.test(ConeProperty::Approximate) && ToCompute.test(ConeProperty::Deg1Elements)) {
3164         FC.do_approximation = true;
3165         FC.do_deg1_elements = true;
3166     }
3167 
3168     if (ToCompute.test(ConeProperty::DefaultMode)) {
3169         FC.do_default_mode = true;
3170     }
3171     if (ToCompute.test(ConeProperty::BottomDecomposition)) {
3172         FC.do_bottom_dec = true;
3173     }
3174     if (ToCompute.test(ConeProperty::NoBottomDec)) {
3175         FC.suppress_bottom_dec = true;
3176     }
3177     if (ToCompute.test(ConeProperty::KeepOrder) && !dual_original_generators) {
3178         FC.keep_order = true; // The second condition restricts KeepOrder to the dual cone if the input
3179                               // was inequalities
3180     }
3181     if (ToCompute.test(ConeProperty::ClassGroup)) {
3182         FC.do_class_group = true;
3183     }
3184     if (ToCompute.test(ConeProperty::ModuleRank)) {
3185         FC.do_module_rank = true;
3186     }
3187 
3188     if (ToCompute.test(ConeProperty::HSOP)) {
3189         FC.do_hsop = true;
3190     }
3191 
3192     /* Give extra data to FC */
3193     if (isComputed(ConeProperty::ExtremeRays)) {
3194         FC.Extreme_Rays_Ind = ExtremeRaysIndicator;
3195         FC.is_Computed.set(ConeProperty::ExtremeRays);
3196     }
3197 
3198     /* if(isComputed(ConeProperty::Deg1Elements)){
3199         Matrix<IntegerFC> Deg1Converted;
3200         BasisChangePointed.convert_to_sublattice(Deg1Converted, Deg1Elements);
3201         for(size_t i=0;i<Deg1Elements.nr_of_rows();++i)
3202             FC.Deg1_Elements.push_back(Deg1Converted[i]);
3203         FC.is_Computed.set(ConeProperty::Deg1Elements);
3204     }*/
3205 
3206     if (HilbertBasisRecCone.nr_of_rows() > 0) {
3207         BasisChangePointed.convert_to_sublattice(FC.HilbertBasisRecCone, HilbertBasisRecCone);
3208     }
3209 
3210     if (ExcludedFaces.nr_of_rows() != 0) {
3211         BasisChangePointed.convert_to_sublattice_dual(FC.ExcludedFaces, ExcludedFaces);
3212     }
3213     if (isComputed(ConeProperty::ExcludedFaces)) {
3214         FC.is_Computed.set(ConeProperty::ExcludedFaces);
3215     }
3216 
3217     if (inhomogeneous) {
3218         BasisChangePointed.convert_to_sublattice_dual_no_div(FC.Truncation, Dehomogenization);
3219     }
3220     if (Grading.size() > 0) {  // IMPORTANT: Truncation must be set before Grading
3221         if (ToCompute.test(ConeProperty::NoGradingDenom))
3222             BasisChangePointed.convert_to_sublattice_dual_no_div(FC.Grading, Grading);
3223         else
3224             BasisChangePointed.convert_to_sublattice_dual(FC.Grading, Grading);
3225         if (isComputed(ConeProperty::Grading)) {  // is grading positive?
3226             FC.is_Computed.set(ConeProperty::Grading);
3227         }
3228     }
3229 
3230     if (ToCompute.test(ConeProperty::Automorphisms)){
3231         FC.do_automorphisms = true;
3232         FC.quality_of_automorphisms = AutomParam::integral; // if necessary changed into
3233                                                             // algebtraic in full_cone.cpp
3234     }
3235 
3236     if (ToCompute.test(ConeProperty::RationalAutomorphisms)){
3237         FC.do_automorphisms = true;
3238         FC.quality_of_automorphisms = AutomParam::rational;
3239     }
3240 
3241     /*
3242         // if (ToCompute.test(ConeProperty::ExploitIsosMult)) { DONE VIA DESCENT
3243         //    FC.exploit_automs_mult = true;
3244         // }
3245         if (ToCompute.test(ConeProperty::ExploitAutomsVectors)) {
3246             FC.exploit_automs_vectors = true;
3247         }
3248         FC.autom_codim_vectors = autom_codim_vectors;
3249         FC.autom_codim_mult = autom_codim_mult;
3250     }*/
3251 
3252     if (SupportHyperplanes.nr_of_rows() != 0) {
3253         BasisChangePointed.convert_to_sublattice_dual(FC.Support_Hyperplanes, SupportHyperplanes);
3254     }
3255     if (isComputed(ConeProperty::SupportHyperplanes)) {
3256         FC.is_Computed.set(ConeProperty::SupportHyperplanes);
3257         FC.do_all_hyperplanes = false;
3258     }
3259 
3260     if (is_approximation)
3261         give_data_of_approximated_cone_to(FC);
3262 
3263     bool must_triangulate = FC.do_h_vector || FC.do_Hilbert_basis || FC.do_multiplicity || FC.do_Stanley_dec ||
3264                             FC.do_module_rank || FC.do_module_gens_intcl || FC.do_bottom_dec || FC.do_hsop ||
3265                             FC.do_integrally_closed || FC.keep_triangulation || FC.do_integrally_closed || FC.do_cone_dec ||
3266                             FC.do_determinants || FC.do_triangulation_size || FC.do_deg1_elements || FC.do_default_mode;
3267 
3268     // Do we really need the Full_Cone? ALREADY CHECKED
3269 
3270     /* if (!must_triangulate && !FC.do_automorphisms && isComputed(ConeProperty::SupportHyperplanes) &&
3271         isComputed(ConeProperty::ExtremeRays) && !ToCompute.test(ConeProperty::Grading) &&
3272         !ToCompute.test(ConeProperty::IsPointed) && !ToCompute.test(ConeProperty::ClassGroup) &&
3273         !ToCompute.test(ConeProperty::IsEmptySemiOpen) )
3274         return; */
3275 
3276     // restore if usaeful
3277     if (!must_triangulate && keep_convex_hull_data && ConvHullData.SLR.equal(BasisChangePointed) &&
3278         ConvHullData.nr_threads == omp_get_max_threads() && ConvHullData.Generators.nr_of_rows() > 0) {
3279         FC.keep_order = true;
3280         FC.restore_previous_computation(ConvHullData, true);  // true = primal
3281     }
3282 
3283     /* do the computation */
3284 
3285     try {
3286         try {
3287             FC.compute();
3288         } catch (const NotIntegrallyClosedException&) {
3289         }
3290         setComputed(ConeProperty::Sublattice);
3291         extract_data(FC, ToCompute);
3292         ToCompute.reset(is_Computed);
3293         // make sure we minimize the excluded faces if requested
3294         if (ToCompute.test(ConeProperty::ExcludedFaces) || ToCompute.test(ConeProperty::SupportHyperplanes)) {
3295             FC.prepare_inclusion_exclusion();  // WHY THIS ??????
3296         }
3297         if (isComputed(ConeProperty::IsPointed) && pointed)
3298             setComputed(ConeProperty::MaximalSubspace);
3299     } catch (const NonpointedException&) {
3300 
3301         setComputed(ConeProperty::Sublattice);
3302         extract_data(FC, ToCompute);
3303         if (verbose) {
3304             verboseOutput() << "Cone not pointed. Restarting computation." << endl;
3305         }
3306         FC = Full_Cone<IntegerFC>(Matrix<IntegerFC>(1));  // to kill the old FC (almost)
3307         pass_to_pointed_quotient();
3308         compute_full_cone_inner<IntegerFC>(ToCompute);
3309     }
3310 }
3311 
3312 //---------------------------------------------------------------------------
3313 
3314 template <typename Integer>
compute_integer_hull()3315 void Cone<Integer>::compute_integer_hull() {
3316     if (isComputed(ConeProperty::IntegerHull))
3317         return;
3318 
3319     if (verbose) {
3320         verboseOutput() << "Computing integer hull" << endl;
3321     }
3322 
3323     Matrix<Integer> IntHullGen;
3324     bool IntHullComputable = true;
3325     // size_t nr_extr = 0;
3326     if (inhomogeneous) {
3327         if ((!using_renf<Integer>() && !isComputed(ConeProperty::HilbertBasis)) ||
3328             (using_renf<Integer>() && !isComputed(ConeProperty::ModuleGenerators)))
3329             IntHullComputable = false;
3330         if (using_renf<Integer>())
3331             IntHullGen = ModuleGenerators;
3332         else {
3333             IntHullGen = HilbertBasis;  // not defined in case of renf_elem_class
3334             IntHullGen.append(ModuleGenerators);
3335         }
3336     }
3337     else {
3338         if (!isComputed(ConeProperty::Deg1Elements))
3339             IntHullComputable = false;
3340         IntHullGen = Deg1Elements;
3341     }
3342     ConeProperties IntHullCompute;
3343     IntHullCompute.set(ConeProperty::SupportHyperplanes);
3344     if (!IntHullComputable) {
3345         errorOutput() << "Integer hull not computable: no integer points available." << endl;
3346         throw NotComputableException(IntHullCompute);
3347     }
3348 
3349     if (IntHullGen.nr_of_rows() == 0) {
3350         IntHullGen.append(vector<Integer>(dim, 0));  // we need a non-empty input matrix
3351     }
3352 
3353     INTERRUPT_COMPUTATION_BY_EXCEPTION
3354 
3355     if (!inhomogeneous || HilbertBasis.nr_of_rows() == 0) {  // polytoe since homogeneous or recession coe = 0
3356         // nr_extr = IntHullGen.extreme_points_first(verbose);         // don't need a norm here since all points have degree or level 1
3357     }
3358     else {  // now an unbounded polyhedron
3359         if (isComputed(ConeProperty::Grading)) {
3360             //nr_extr = IntHullGen.extreme_points_first(verbose,Grading);
3361             IntHullNorm  =Grading;
3362         }
3363         else {
3364             if (isComputed(ConeProperty::SupportHyperplanes)) {
3365                 IntHullNorm = SupportHyperplanes.find_inner_point();
3366                 // nr_extr = IntHullGen.extreme_points_first(verbose,aux_grading);
3367             }
3368         }
3369     }
3370 
3371     /* if (verbose) {
3372         verboseOutput() << nr_extr << " extreme points found" << endl;
3373     }*/
3374 
3375     // IntHullGen.pretty_print(cout);
3376 
3377     if (IntHullCone != NULL)
3378         delete IntHullCone;
3379 
3380     if (!using_renf<Integer>())
3381         IntHullCone = new Cone<Integer>(InputType::cone_and_lattice, IntHullGen, Type::subspace, BasisMaxSubspace);
3382     else
3383         IntHullCone = new Cone<Integer>(InputType::cone, IntHullGen, Type::subspace, BasisMaxSubspace);
3384     /* if (nr_extr != 0)  // we suppress the ordering in full_cone only if we have found few extreme rays
3385         IntHullCompute.set(ConeProperty::KeepOrder);*/
3386 
3387     IntHullCone->setRenf(RenfSharedPtr);
3388 
3389     IntHullCone->inhomogeneous = true;  // inhomogeneous;
3390     IntHullCone->is_inthull_cone = true;
3391     IntHullCone->HilbertBasis = HilbertBasis;
3392     IntHullCone->ModuleGenerators = ModuleGenerators;
3393     IntHullCone->setComputed(ConeProperty::HilbertBasis);
3394     IntHullCone->setComputed(ConeProperty::ModuleGenerators);
3395     if (inhomogeneous)
3396         IntHullCone->Dehomogenization = Dehomogenization;
3397     else
3398         IntHullCone->Dehomogenization = Grading;
3399     IntHullCone->verbose = verbose;
3400     IntHullCompute.set(ConeProperty::FullConeDynamic);
3401     try {
3402         IntHullCone->compute(IntHullCompute);
3403         if (IntHullCone->isComputed(ConeProperty::SupportHyperplanes))
3404             setComputed(ConeProperty::IntegerHull);
3405         if (verbose) {
3406             verboseOutput() << "Integer hull finished" << endl;
3407         }
3408     } catch (const NotComputableException&) {
3409         errorOutput() << "Error in computation of integer hull" << endl;
3410     }
3411 }
3412 
3413 //---------------------------------------------------------------------------
3414 
3415 template <typename Integer>
compute(ConeProperty::Enum cp)3416 ConeProperties Cone<Integer>::compute(ConeProperty::Enum cp) {
3417     if (isComputed(cp))
3418         return ConeProperties();
3419     return compute(ConeProperties(cp));
3420 }
3421 
3422 template <typename Integer>
compute(ConeProperty::Enum cp1,ConeProperty::Enum cp2)3423 ConeProperties Cone<Integer>::compute(ConeProperty::Enum cp1, ConeProperty::Enum cp2) {
3424     if (isComputed(cp1) && isComputed(cp2))
3425         return ConeProperties();
3426     return compute(ConeProperties(cp1, cp2));
3427 }
3428 
3429 template <typename Integer>
compute(ConeProperty::Enum cp1,ConeProperty::Enum cp2,ConeProperty::Enum cp3)3430 ConeProperties Cone<Integer>::compute(ConeProperty::Enum cp1, ConeProperty::Enum cp2, ConeProperty::Enum cp3) {
3431     if (isComputed(cp1) && isComputed(cp2) && isComputed(cp3))
3432         return ConeProperties();
3433     return compute(ConeProperties(cp1, cp2, cp3));
3434 }
3435 
3436 //---------------------------------------------------------------------------
3437 
3438 template <typename Integer>
set_implicit_dual_mode(ConeProperties & ToCompute)3439 void Cone<Integer>::set_implicit_dual_mode(ConeProperties& ToCompute) {
3440     if (ToCompute.test(ConeProperty::DualMode) || ToCompute.test(ConeProperty::PrimalMode) ||
3441         ToCompute.test(ConeProperty::ModuleGeneratorsOverOriginalMonoid) || ToCompute.test(ConeProperty::Approximate) ||
3442         ToCompute.test(ConeProperty::Projection) || nr_cone_gen > 0 ||
3443         SupportHyperplanes.nr_of_rows() > 2 * dim ||
3444         SupportHyperplanes.nr_of_rows() <= BasisChangePointed.getRank() + 50 / (BasisChangePointed.getRank() + 1))
3445         return;
3446     if (ToCompute.test(ConeProperty::HilbertBasis))
3447         ToCompute.set(ConeProperty::DualMode);
3448     if (ToCompute.test(ConeProperty::Deg1Elements) &&
3449         !(ToCompute.test(ConeProperty::HilbertSeries) || ToCompute.test(ConeProperty::Multiplicity)))
3450         ToCompute.set(ConeProperty::DualMode);
3451     return;
3452 }
3453 
3454 // If this function is called, either no type of automorphisms has been computed
3455 // or the computed one is different than the one asked for.
3456 // So we can reset all of them.
3457 template <typename Integer>
prepare_automorphisms(const ConeProperties & ToCompute)3458 void Cone<Integer>::prepare_automorphisms(const ConeProperties& ToCompute) {
3459 
3460     ConeProperties ToCompute_Auto = ToCompute.intersection_with(all_automorphisms());
3461     if(ToCompute_Auto.none())
3462         return;
3463     is_Computed.reset(all_automorphisms());
3464 }
3465 
3466 // Similarly for triangulations
3467 template <typename Integer>
prepare_refined_triangulation(const ConeProperties & ToCompute)3468 void Cone<Integer>::prepare_refined_triangulation(const ConeProperties& ToCompute) {
3469 
3470     ConeProperties ToCompute_Tri = ToCompute.intersection_with(all_triangulations());
3471     if(ToCompute_Tri.none())
3472         return;
3473     is_Computed.reset(all_triangulations());
3474 }
3475 
3476 template <typename Integer>
handle_dynamic(const ConeProperties & ToCompute)3477 void Cone<Integer>::handle_dynamic(const ConeProperties& ToCompute) {
3478     if (ToCompute.test(ConeProperty::Dynamic))
3479         keep_convex_hull_data = true;
3480     if (ToCompute.test(ConeProperty::Static))
3481         keep_convex_hull_data = false;
3482 
3483     AddGenerators.resize(0, dim);
3484     AddInequalities.resize(0, dim);
3485 }
3486 
3487 #ifdef NMZ_EXTENDED_TESTS
3488 
3489 extern long SimplexParallelEvaluationBound;
3490 
3491 template <typename Integer>
set_extended_tests(ConeProperties & ToCompute)3492 void Cone<Integer>::set_extended_tests(ConeProperties& ToCompute){
3493     if(ToCompute.test(ConeProperty::TestArithOverflowFullCone))
3494         test_arith_overflow_full_cone=true;
3495     if(ToCompute.test(ConeProperty::TestArithOverflowDualMode))
3496         test_arith_overflow_dual_mode=true;
3497     if(ToCompute.test(ConeProperty::TestArithOverflowDescent))
3498         test_arith_overflow_descent=true;
3499     if(ToCompute.test(ConeProperty::TestArithOverflowProjAndLift))
3500         test_arith_overflow_proj_and_lift=true;
3501     if(ToCompute.test(ConeProperty::TestSmallPyramids))
3502         test_small_pyramids=true;
3503     if(ToCompute.test(ConeProperty::TestLargePyramids)){
3504         test_large_pyramids=true;
3505         test_small_pyramids=true;
3506     }
3507     if(ToCompute.test(ConeProperty::TestLinearAlgebraGMP)){
3508         test_linear_algebra_GMP=true;
3509         if(isComputed(ConeProperty::OriginalMonoidGenerators)){
3510             Matrix<MachineInteger> GenLL;
3511             convert(GenLL,Generators);
3512             if(GenLL.rank()==dim){
3513                 MachineInteger test=GenLL.full_rank_index(); // to test full_rank_index with "overflow"
3514                 assert(convertTo<Integer>(test)==internal_index);
3515             }
3516             MachineInteger test_rank;
3517             test_rank=GenLL.row_echelon_reduce(); // same reason as above
3518             assert(convertTo<Integer>(test_rank)==Generators.rank());
3519         }
3520 
3521     }
3522     if(ToCompute.test(ConeProperty::TestSimplexParallel)){
3523         test_simplex_parallel=true;
3524         ToCompute.set(ConeProperty::NoSubdivision);
3525         SimplexParallelEvaluationBound =0;
3526     }
3527 
3528     if(ToCompute.test(ConeProperty::TestLibNormaliz)){
3529         run_additional_tests_libnormaliz();
3530     }
3531 }
3532 #endif
3533 
3534 //---------------------------------------------------------------------------
3535 
3536 template <typename Integer>
compute(ConeProperties ToCompute)3537 ConeProperties Cone<Integer>::compute(ConeProperties ToCompute) {
3538 
3539     // cout << "AAAA " << ToCompute << " IIIII " << inhomogeneous <<  endl;;
3540 
3541     size_t nr_computed_at_start = is_Computed.count();
3542 
3543     handle_dynamic(ToCompute);
3544 
3545     set_parallelization();
3546     nmz_interrupted = 0;
3547 
3548     ToCompute.reset(is_Computed);
3549     if (ToCompute.none()) {
3550         return ConeProperties();
3551     }
3552 
3553     // We want to make sure that the exckuded faces are shown in the output/can be returned
3554     if(!isComputed(ConeProperty::ExcludedFaces) && ExcludedFaces.nr_of_rows() > 0)
3555         ToCompute.set(ConeProperty::ExcludedFaces);
3556 
3557 #ifdef NMZ_EXTENDED_TESTS
3558     set_extended_tests(ToCompute);
3559 #endif
3560 
3561     if (general_no_grading_denom || inhomogeneous)
3562         ToCompute.set(ConeProperty::NoGradingDenom);
3563 
3564     if (ToCompute.test(ConeProperty::GradingIsPositive)) {
3565         if (Grading.size() == 0)
3566             throw BadInputException("No grading declared that could be positive.");
3567         else
3568             setComputed(ConeProperty::Grading);
3569     }
3570 
3571     if(ToCompute.test(ConeProperty::NoGradingDenom)){
3572         GradingDenom = 1;
3573         setComputed(ConeProperty::GradingDenom);
3574     }
3575 
3576     if (ToCompute.test(ConeProperty::NoPeriodBound)) {
3577         HSeries.set_period_bounded(false);
3578         IntData.getWeightedEhrhartSeries().first.set_period_bounded(false);
3579     }
3580 
3581 #ifndef NMZ_COCOA
3582     if (ToCompute.test(ConeProperty::VirtualMultiplicity) || ToCompute.test(ConeProperty::Integral) ||
3583         ToCompute.test(ConeProperty::WeightedEhrhartSeries))
3584         throw BadInputException("Integral, VirtualMultiplicity, WeightedEhrhartSeries only computable with CoCoALib");
3585 #endif
3586 
3587 #ifndef NMZ_NAUTY
3588      if ( ToCompute.intersection_with(all_automorphisms()).any())
3589         throw BadInputException("automorphism groups only computable with nauty");
3590 #endif
3591 
3592     // default_mode=ToCompute.test(ConeProperty::DefaultMode);
3593 
3594     if (ToCompute.test(ConeProperty::BigInt)) {
3595         if (!using_GMP<Integer>())
3596             throw BadInputException("BigInt can only be set for cones of Integer type GMP");
3597         change_integer_type = false;
3598     }
3599 
3600     // we don't want a different order of the generators if an order sensitive goal
3601     // has already been computed
3602     if( isComputed(ConeProperty::BasicTriangulation) || isComputed(ConeProperty::PullingTriangulation) ){
3603         Generators = BasicTriangulation.second;
3604         ToCompute.set(ConeProperty::KeepOrder);
3605         is_Computed.reset(ConeProperty::ExtremeRays); // we may have lost ExtremeRaysIndicator
3606     }
3607 
3608     if( (ToCompute.test(ConeProperty::PullingTriangulation) || ToCompute.test(ConeProperty::PlacingTriangulation) )
3609             && !isComputed(ConeProperty::Generators) )
3610         throw BadInputException("Placing/pulling tiangulation only computable with generator input");
3611 
3612     if(ToCompute.test(ConeProperty::IsEmptySemiOpen) && ExcludedFaces.nr_of_rows() == 0)
3613         throw BadInputException("IsEmptySemiOpen can only be computed with excluded faces");
3614 
3615     INTERRUPT_COMPUTATION_BY_EXCEPTION
3616 
3617     if (BasisMaxSubspace.nr_of_rows() > 0 && !isComputed(ConeProperty::MaximalSubspace)) {
3618         BasisMaxSubspace = Matrix<Integer>(0, dim);
3619         if(ToCompute.test(ConeProperty::FullConeDynamic)) // if integer hull is computed
3620             compute(ConeProperty::MaximalSubspace, ConeProperty::FullConeDynamic);
3621         else
3622             compute(ConeProperty::MaximalSubspace);
3623     }
3624 
3625     /*
3626     // must distiguish it from being set through DefaultMode; -- DONE VIA FDefaultMode
3627 
3628     if(ToCompute.test(ConeProperty::HilbertSeries) || ToCompute.test(ConeProperty::HSOP)
3629                || ToCompute.test(ConeProperty::EhrhartSeries) || ToCompute.test(ConeProperty::HilbertQuasiPolynomial)
3630                || ToCompute.test(ConeProperty::EhrhartQuasiPolynomial))
3631         ToCompute.set(ConeProperty::ExplicitHilbertSeries);
3632     */
3633 
3634     // to control the computation of rational solutions in the inhomogeneous case
3635     if (ToCompute.test(ConeProperty::DualMode) &&
3636         !(ToCompute.test(ConeProperty::HilbertBasis) || ToCompute.test(ConeProperty::Deg1Elements) ||
3637           ToCompute.test(ConeProperty::ModuleGenerators) || ToCompute.test(ConeProperty::LatticePoints))) {
3638         ToCompute.set(ConeProperty::NakedDual);
3639     }
3640     // to control the computation of rational solutions in the inhomogeneous case
3641 
3642     if(using_renf<Integer>())
3643         ToCompute.check_Q_permissible(false);  // before implications!
3644 
3645     ToCompute.check_conflicting_variants();
3646     ToCompute.set_preconditions(inhomogeneous, using_renf<Integer>());
3647 
3648     if(using_renf<Integer>())
3649         ToCompute.check_Q_permissible(true);  // after implications!
3650 
3651     if(ToCompute.test(ConeProperty::Sublattice) && !isComputed(ConeProperty::Generators))
3652         ToCompute.set(ConeProperty::ExtremeRays, ConeProperty::SupportHyperplanes);
3653 
3654     ToCompute.check_sanity(inhomogeneous);
3655     if (inhomogeneous) {
3656         if (Grading.size() == 0) {
3657             if (ToCompute.test(ConeProperty::DefaultMode)) {
3658                 ToCompute.reset(ConeProperty::HilbertSeries);
3659             }
3660             ToCompute.reset(ConeProperty::NoGradingDenom);
3661         }
3662     }
3663 
3664     prepare_refined_triangulation(ToCompute);
3665     prepare_automorphisms(ToCompute);
3666 
3667     // ToCompute.set_default_goals(inhomogeneous,using_renf<renf_elem_class>());
3668     ToCompute.check_sanity(inhomogeneous);
3669 
3670     ToCompute.reset(is_Computed);
3671     if (ToCompute.none()) {
3672         return ConeProperties();
3673     }
3674     if (!isComputed(ConeProperty::OriginalMonoidGenerators)) {
3675         if (ToCompute.test(ConeProperty::ModuleGeneratorsOverOriginalMonoid)) {
3676             errorOutput() << "ERROR: Module generators over original monoid only computable if original monoid is defined!"
3677                           << endl;
3678             throw NotComputableException(ConeProperty::ModuleGeneratorsOverOriginalMonoid);
3679         }
3680         if (ToCompute.test(ConeProperty::IsIntegrallyClosed)) {
3681             errorOutput() << "ERROR: Original monoid is not defined, cannot check it for being integrally closed." << endl;
3682             throw NotComputableException(ConeProperty::IsIntegrallyClosed);
3683         }
3684     }
3685 
3686     // to protect against intermediate computaions of generators in interactive use
3687     if (ToCompute.test(ConeProperty::ModuleGeneratorsOverOriginalMonoid) || ToCompute.test(ConeProperty::IsIntegrallyClosed) ) {
3688         Generators = InputGenerators;
3689         is_Computed.reset(ConeProperty::ExtremeRays);
3690     }
3691 
3692     compute_ambient_automorphisms(ToCompute);
3693     compute_input_automorphisms(ToCompute);
3694     ToCompute.reset(is_Computed);
3695     if (ToCompute.none()) {
3696         return ConeProperties();
3697     }
3698 
3699     if(ToCompute.test(ConeProperty::PullingTriangulation))
3700         compute_refined_triangulation(ToCompute);
3701 
3702     ToCompute.reset(is_Computed);
3703     if (ToCompute.none()) {
3704         return ConeProperties();
3705     }
3706 
3707     if (conversion_done)
3708         compute_generators(ToCompute);
3709 
3710     ToCompute.reset(is_Computed);
3711     if (ToCompute.none()) {     // IMPORTANT: do not use goals() at this point because it would prevent
3712         return ConeProperties();  // HSOP if HSOP is applied to an already computed Hilbert series
3713     }                             // Alternatively one could do complete_HilbertSeries_comp(ToCompute)
3714                                   // at the very beginning of this function
3715 
3716     /*if(ToCompute.test(ConeProperty::IsEmptySemiOpen) && !isComputed(ConeProperty::IsEmptySemiOpen)){
3717         compute_generators(ToCompute);
3718         ConeProperties ToComputeFirst;
3719         ToComputeFirst.set(ConeProperty::Generators);
3720         ToComputeFirst.set(ConeProperty::SupportHyperplanes);
3721         ToComputeFirst.set(ConeProperty::ExtremeRays);
3722         ToComputeFirst.set(ConeProperty::IsEmptySemiOpen);
3723         compute_full_cone(ToComputeFirst);
3724         ToCompute.reset(is_Computed);
3725     }*/
3726 
3727     check_integrally_closed(ToCompute); // check cheap necessary conditions
3728 
3729     if (rees_primary && ToCompute.test(ConeProperty::Multiplicity)) // for backward compatibility
3730         ToCompute.set(ConeProperty::ReesPrimaryMultiplicity);
3731 
3732     try_multiplicity_of_para(ToCompute);
3733     ToCompute.reset(is_Computed);
3734 
3735     try_signed_dec(ToCompute);
3736     ToCompute.reset(is_Computed);
3737 
3738     if(ToCompute.test(ConeProperty::Integral) || ToCompute.test(ConeProperty::VirtualMultiplicity))
3739         ToCompute.set(ConeProperty::BasicTriangulation); // Hasn't been done by signed dec.
3740 
3741     try_multiplicity_by_descent(ToCompute);
3742     ToCompute.reset(is_Computed);
3743 
3744     try_symmetrization(ToCompute);
3745     ToCompute.reset(is_Computed);
3746 
3747     complete_HilbertSeries_comp(ToCompute);
3748 
3749     complete_sublattice_comp(ToCompute);
3750     if (ToCompute.goals().none()) {
3751         return ConeProperties();
3752     }
3753 
3754     INTERRUPT_COMPUTATION_BY_EXCEPTION
3755 
3756     compute_projection(ToCompute);
3757 
3758     INTERRUPT_COMPUTATION_BY_EXCEPTION
3759 
3760 #ifdef ENFNORMALIZ
3761     if(using_renf<Integer>())
3762         prepare_volume_computation(ToCompute);
3763 #endif
3764 
3765     treat_polytope_as_being_hom_defined(ToCompute);  // if necessary
3766 
3767     ToCompute.reset(is_Computed);  // already computed
3768 
3769     complete_HilbertSeries_comp(ToCompute);
3770 
3771     complete_sublattice_comp(ToCompute);
3772     if (ToCompute.goals().none()) {
3773         return ConeProperties();
3774     }
3775 
3776     if(!using_renf<Integer>())
3777         try_approximation_or_projection(ToCompute);
3778 
3779     ToCompute.reset(is_Computed);
3780     if (ToCompute.goals().none()) {
3781         return ConeProperties();
3782     }
3783 
3784     INTERRUPT_COMPUTATION_BY_EXCEPTION
3785 
3786     set_implicit_dual_mode(ToCompute);
3787 
3788     if (ToCompute.test(ConeProperty::DualMode)) {
3789         compute_dual(ToCompute);
3790     }
3791 
3792     if (ToCompute.test(ConeProperty::WitnessNotIntegrallyClosed)) {
3793         find_witness(ToCompute);
3794     }
3795 
3796     ToCompute.reset(is_Computed);
3797     complete_HilbertSeries_comp(ToCompute);
3798     complete_sublattice_comp(ToCompute);
3799     if (ToCompute.goals().none()) {
3800         return ConeProperties();
3801     }
3802 
3803     INTERRUPT_COMPUTATION_BY_EXCEPTION
3804 
3805     /* preparation: get generators if necessary */
3806 
3807     // cout << "FFFF " << ToCompute.full_cone_goals(using_renf<Integer>()) << endl;
3808 
3809     if (ToCompute.full_cone_goals(using_renf<Integer>()).any()) {
3810         compute_generators(ToCompute);
3811         if (!isComputed(ConeProperty::Generators)) {
3812             throw FatalException("Could not get Generators.");
3813         }
3814     }
3815     ToCompute.reset(is_Computed);
3816 
3817     /* cout << "TTTT " << ToCompute.full_cone_goals(using_renf<Integer>()) << endl;*/
3818     /* cout << "TTTT IIIII  " << ToCompute.full_cone_goals() << endl;*/
3819 
3820     if (rees_primary && (ToCompute.test(ConeProperty::ReesPrimaryMultiplicity) ||
3821                          ToCompute.test(ConeProperty::HilbertSeries) || ToCompute.test(ConeProperty::DefaultMode))) {
3822         ReesPrimaryMultiplicity = compute_primary_multiplicity();
3823         setComputed(ConeProperty::ReesPrimaryMultiplicity);
3824     }
3825 
3826     ToCompute.reset(is_Computed);
3827     complete_HilbertSeries_comp(ToCompute);
3828     complete_sublattice_comp(ToCompute);
3829     if (ToCompute.goals().none()) {
3830         return ConeProperties();
3831     }
3832 
3833     if(!using_renf<Integer>())
3834         try_Hilbert_Series_from_lattice_points(ToCompute);
3835     ToCompute.reset(is_Computed);
3836     complete_HilbertSeries_comp(ToCompute);
3837     complete_sublattice_comp(ToCompute);
3838     if (ToCompute.goals().none()) {
3839         return ConeProperties();
3840     }
3841 
3842     // the actual computation
3843 
3844     if (isComputed(ConeProperty::SupportHyperplanes) && using_renf<Integer>())
3845         ToCompute.reset(ConeProperty::DefaultMode);
3846 
3847     /* cout << "UUUU " << ToCompute.full_cone_goals(using_renf<Integer>()) << endl;*/
3848     /* cout << "UUUU All  " << ToCompute << endl;
3849     cout << "UUUU  IIIII  " << ToCompute.full_cone_goals() << endl;*/
3850 
3851     compute_rational_data(ToCompute);
3852     ToCompute.reset(is_Computed);
3853     if (ToCompute.goals().none()) {
3854         return ConeProperties();
3855     }
3856 
3857     // the computation of the full cone
3858     if (ToCompute.full_cone_goals(using_renf<Integer>()).any()) {
3859         compute_full_cone(ToCompute);
3860     }
3861 
3862     // cout << " VVVV " << ToCompute.full_cone_goals() << endl;
3863 
3864      if (ToCompute.test(ConeProperty::WitnessNotIntegrallyClosed)) {
3865         find_witness(ToCompute);
3866     }
3867 
3868     if(using_renf<Integer>())
3869         compute_lattice_points_in_polytope(ToCompute);
3870     ToCompute.reset(is_Computed);  // already computed
3871 
3872     if(precomputed_extreme_rays && inhomogeneous)
3873         compute_affine_dim_and_recession_rank();
3874 
3875     compute_combinatorial_automorphisms(ToCompute);
3876     compute_euclidean_automorphisms(ToCompute);
3877 
3878     make_face_lattice(ToCompute);
3879 
3880     compute_volume(ToCompute);
3881 
3882     check_Gorenstein(ToCompute);
3883 
3884     if (ToCompute.test(ConeProperty::IntegerHull)) {
3885         compute_integer_hull();
3886     }
3887 
3888     compute_refined_triangulation(ToCompute);
3889     make_StanleyDec_export(ToCompute);
3890 
3891     INTERRUPT_COMPUTATION_BY_EXCEPTION
3892 
3893     complete_HilbertSeries_comp(ToCompute);
3894     complete_sublattice_comp(ToCompute);
3895 
3896     compute_vertices_float(ToCompute);
3897     compute_supp_hyps_float(ToCompute);
3898     compute_extreme_rays_float(ToCompute);
3899 
3900     if (ToCompute.test(ConeProperty::WeightedEhrhartSeries))
3901         compute_weighted_Ehrhart(ToCompute);
3902     ToCompute.reset(is_Computed);
3903 
3904     if (ToCompute.test(ConeProperty::Integral))
3905         compute_integral(ToCompute);
3906     ToCompute.reset(is_Computed);
3907 
3908     if (ToCompute.test(ConeProperty::VirtualMultiplicity))
3909         compute_virt_mult(ToCompute);
3910     ToCompute.reset(is_Computed);
3911 
3912     // back up solution for excluded faces which are not set if symmetrization has been used
3913     if ( !isComputed(ConeProperty::ExcludedFaces) && ExcludedFaces.nr_of_rows() > 0) {
3914         ExcludedFaces.sort_lex();
3915         setComputed(ConeProperty::ExcludedFaces);
3916     }
3917 
3918     /* check if everything is computed */
3919     ToCompute.reset(is_Computed);  // remove what is now computed
3920     if (ToCompute.test(ConeProperty::Deg1Elements) && isComputed(ConeProperty::Grading)) {
3921         // can happen when we were looking for a witness earlier
3922         if(nr_computed_at_start == is_Computed.count()){ // Prevention of infinte loop
3923             throw FatalException("FATAL: Compute without effect would be repeated. Inform the authors !");
3924         }
3925         compute(ToCompute);
3926     }
3927 
3928     if (!ToCompute.test(ConeProperty::DefaultMode) && ToCompute.goals().any()) {
3929         throw NotComputableException(ToCompute.goals());
3930     }
3931 
3932     ToCompute.reset_compute_options();
3933 
3934     return ToCompute;
3935 }
3936 
3937 
3938 
3939 
3940 //---------------------------------------------------------------------------
3941 
3942 template <typename Integer>
check_vanishing_of_grading_and_dehom()3943 void Cone<Integer>::check_vanishing_of_grading_and_dehom() {
3944     if (Grading.size() > 0) {
3945         vector<Integer> test = BasisMaxSubspace.MxV(Grading);
3946         if (test != vector<Integer>(test.size())) {
3947             throw BadInputException("Grading does not vanish on maximal subspace.");
3948         }
3949     }
3950     if (Dehomogenization.size() > 0) {
3951         vector<Integer> test = BasisMaxSubspace.MxV(Dehomogenization);
3952         if (test != vector<Integer>(test.size())) {
3953             assert(false);
3954             throw BadInputException("Dehomogenization does not vanish on maximal subspace.");
3955         }
3956     }
3957 }
3958 
3959 //---------------------------------------------------------------------------
3960 
3961 template <typename Integer>
compute_generators(ConeProperties & ToCompute)3962 void Cone<Integer>::compute_generators(ConeProperties& ToCompute) {
3963     // create Generators from SupportHyperplanes
3964 
3965     if (!isComputed(ConeProperty::Generators) && (SupportHyperplanes.nr_of_rows() != 0 || inhomogeneous)) {
3966         if (verbose) {
3967             verboseOutput() << "Computing extreme rays as support hyperplanes of the dual cone:" << endl;
3968         }
3969         if (change_integer_type) {
3970             try {
3971                 compute_generators_inner<MachineInteger>(ToCompute);
3972             } catch (const ArithmeticException& e) {
3973                 if (verbose) {
3974                     verboseOutput() << e.what() << endl;
3975                     verboseOutput() << "Restarting with a bigger type." << endl;
3976                 }
3977                 compute_generators_inner<Integer>(ToCompute);
3978             }
3979         }
3980         else {
3981             compute_generators_inner<Integer>(ToCompute);
3982         }
3983     }
3984     /*for(size_t i=0;i<Generators.nr_of_rows();++i){
3985         for(size_t j=0;j<SupportHyperplanes.nr_of_rows();++j)
3986             cout << v_scalar_product(Generators[i],SupportHyperplanes[j]) << endl;
3987     }*/
3988     assert(isComputed(ConeProperty::Generators));
3989 }
3990 
3991 //---------------------------------------------------------------------------
3992 
3993 // computes the basis change to the pointed quotient
3994 template <typename Integer>
pass_to_pointed_quotient()3995 void Cone<Integer>::pass_to_pointed_quotient(){
3996 
3997     if(isComputed(ConeProperty::MaximalSubspace))
3998         return;
3999 
4000     BasisChangePointed = BasisChange;
4001     Matrix<Integer> DualGen = SupportHyperplanes; // must priotect SupportHyperplanes!
4002     BasisChangePointed.compose_with_passage_to_quotient(BasisMaxSubspace,DualGen);
4003 
4004     check_vanishing_of_grading_and_dehom();
4005     setComputed(ConeProperty::MaximalSubspace);
4006 
4007     if (!isComputed(ConeProperty::IsPointed)) {
4008         pointed = (BasisMaxSubspace.nr_of_rows() == 0);
4009         setComputed(ConeProperty::IsPointed);
4010     }
4011 }
4012 
4013 //---------------------------------------------------------------------------
4014 
4015 template <typename Integer>
4016 template <typename IntegerFC>
compute_generators_inner(ConeProperties & ToCompute)4017 void Cone<Integer>::compute_generators_inner(ConeProperties& ToCompute) {
4018 
4019 #ifdef NMZ_EXTENDED_TESTS
4020     if(!using_GMP<IntegerFC>() && !using_renf<IntegerFC>() && test_arith_overflow_full_cone)
4021         throw ArithmeticException(0);
4022 #endif
4023 
4024     pass_to_pointed_quotient();
4025 
4026     // restrict the supphyps to efficient sublattice and push to quotient mod subspace
4027     Matrix<IntegerFC> Dual_Gen_Pointed;
4028     BasisChangePointed.convert_to_sublattice_dual(Dual_Gen_Pointed, SupportHyperplanes);
4029     Full_Cone<IntegerFC> Dual_Cone(Dual_Gen_Pointed);
4030     Dual_Cone.verbose = verbose;
4031     Dual_Cone.renf_degree = renf_degree;
4032     Dual_Cone.do_extreme_rays = true;  // we try to find them, need not exist
4033     if (ToCompute.test(ConeProperty::KeepOrder) && dual_original_generators)
4034         Dual_Cone.keep_order = true;
4035 
4036     if ((keep_convex_hull_data || conversion_done) && ConvHullData.SLR.equal(BasisChangePointed) &&
4037         ConvHullData.nr_threads == omp_get_max_threads() && ConvHullData.Generators.nr_of_rows() > 0) {
4038         conversion_done = false;
4039         Dual_Cone.keep_order = true;
4040         Dual_Cone.restore_previous_computation(ConvHullData, false);  // false=dual
4041     }
4042 
4043     Dual_Cone.keep_convex_hull_data = keep_convex_hull_data;
4044     Dual_Cone.do_pointed = true; // Dual may very well be non-pointed.
4045                             // In this case the support hyperplanes
4046                             // can contain duplictes. There are erased in full_cone.cpp
4047     try { // most likely superfluous, but doesn't harm
4048         Dual_Cone.dualize_cone();
4049     } catch (const NonpointedException&) {
4050     };  // we don't mind if the dual cone is not pointed
4051 
4052     // cout << "GGGGG " << Dual_Cone.is_Computed << endl;
4053 
4054     extract_data_dual(Dual_Cone, ToCompute);
4055 }
4056 
4057 //---------------------------------------------------------------------------
4058 
4059 template <typename Integer>
4060 template <typename IntegerFC>
extract_data_dual(Full_Cone<IntegerFC> & Dual_Cone,ConeProperties & ToCompute)4061 void Cone<Integer>::extract_data_dual(Full_Cone<IntegerFC>& Dual_Cone, ConeProperties& ToCompute) {
4062 
4063    if (Dual_Cone.isComputed(ConeProperty::SupportHyperplanes)) {
4064 
4065         if (keep_convex_hull_data) {
4066             extract_convex_hull_data(Dual_Cone, false);  // false means: dual
4067         }
4068         // get the extreme rays of the primal cone
4069         // BasisChangePointed.convert_from_sublattice(Generators,
4070         //                 Dual_Cone.getSupportHyperplanes());
4071         extract_supphyps(Dual_Cone, Generators, false);  // false means: no dualization
4072         ExtremeRaysIndicator.resize(0);
4073         setComputed(ConeProperty::Generators);
4074 
4075         // get minmal set of support_hyperplanes if possible
4076         if (Dual_Cone.isComputed(ConeProperty::ExtremeRays)) {
4077             Matrix<IntegerFC> Supp_Hyp = Dual_Cone.getGenerators().submatrix(Dual_Cone.getExtremeRays());
4078             BasisChangePointed.convert_from_sublattice_dual(SupportHyperplanes, Supp_Hyp);
4079             if (using_renf<Integer>())
4080                 SupportHyperplanes.standardize_rows();
4081             norm_dehomogenization(BasisChangePointed.getRank());
4082             SupportHyperplanes.sort_lex();
4083             setComputed(ConeProperty::SupportHyperplanes);
4084             addition_constraints_allowed=true;
4085         }
4086 
4087         // now the final transformations
4088         // only necessary if the basis changes computed so far do not make the cone full-dimensional
4089         // the latter is equaivalent to the dual cone bot being pointed
4090          if (!(Dual_Cone.isComputed(ConeProperty::IsPointed) && Dual_Cone.isPointed())) {
4091             // first to full-dimensional pointed
4092             Matrix<Integer> Help;
4093             Help = BasisChangePointed.to_sublattice(Generators);  // sublattice of the primal space
4094             Sublattice_Representation<Integer> PointedHelp(Help, true);
4095             BasisChangePointed.compose(PointedHelp);
4096             // second to efficient sublattice
4097             if (BasisMaxSubspace.nr_of_rows() == 0) {  // primal cone is pointed and we can copy
4098                 BasisChange = BasisChangePointed;
4099             }
4100             else {
4101                 Help = BasisChange.to_sublattice(Generators);
4102                 Help.append(BasisChange.to_sublattice(BasisMaxSubspace));
4103                 Sublattice_Representation<Integer> EmbHelp(Help, true);  // sublattice of the primal space
4104                 compose_basis_change(EmbHelp);
4105             }
4106         }
4107         setComputed(ConeProperty::Sublattice);  // will not be changed anymore
4108 
4109         checkGrading(!ToCompute.test(ConeProperty::NoGradingDenom));
4110         // compute grading, so that it is also known if nothing else is done afterwards
4111         // it is only done if the denominator is 1, like in full_cone.cpp
4112         if (!isComputed(ConeProperty::Grading) && !inhomogeneous && !using_renf<Integer>()) {
4113             // Generators = ExtremeRays
4114             // we only do it if the cone is pointed
4115             vector<Integer> lf = BasisChangePointed.to_sublattice(Generators).find_linear_form();
4116             if (lf.size() == BasisChange.getRank()) {
4117                 vector<Integer> test_lf = BasisChange.from_sublattice_dual(lf);
4118                 if (Generators.nr_of_rows() == 0 || v_scalar_product(Generators[0], test_lf) == 1) {
4119                     setGrading(test_lf);
4120                     deg1_extreme_rays = true;
4121                     setComputed(ConeProperty::IsDeg1ExtremeRays);
4122                 }
4123             }
4124         }
4125         setWeights();
4126         set_extreme_rays(vector<bool>(Generators.nr_of_rows(), true));
4127         addition_generators_allowed = true;
4128     }
4129 }
4130 
4131 //---------------------------------------------------------------------------
4132 
4133 template <typename Integer>
compute_dual(ConeProperties & ToCompute)4134 void Cone<Integer>::compute_dual(ConeProperties& ToCompute) {
4135     ToCompute.reset(is_Computed);
4136     if (ToCompute.goals().none() || !(ToCompute.test(ConeProperty::Deg1Elements) || ToCompute.test(ConeProperty::HilbertBasis))) {
4137         return;
4138     }
4139 
4140     if (change_integer_type) {
4141         try {
4142             compute_dual_inner<MachineInteger>(ToCompute);
4143         } catch (const ArithmeticException& e) {
4144             if (verbose) {
4145                 verboseOutput() << e.what() << endl;
4146                 verboseOutput() << "Restarting with a bigger type." << endl;
4147             }
4148             change_integer_type = false;
4149         }
4150     }
4151 
4152     if (!change_integer_type) {
4153         if (!using_GMP<Integer>() && !ToCompute.test(ConeProperty::DefaultMode)) {
4154             compute_dual_inner<Integer>(ToCompute);
4155         }
4156         else {
4157             try {
4158                 compute_dual_inner<Integer>(ToCompute);
4159             } catch (const ArithmeticException& e) {  // the nonly reason for failure is an overflow in a degree computation
4160                 if (verbose) {                        // so we can relax in default mode
4161                     verboseOutput() << e.what() << endl;
4162                     verboseOutput() << "Reducing computation goals." << endl;
4163                 }
4164                 ToCompute.reset(ConeProperty::HilbertBasis);
4165                 ToCompute.reset(ConeProperty::HilbertSeries);
4166                 // we cannot do more here
4167             }
4168         }
4169     }
4170 
4171     ToCompute.reset(ConeProperty::DualMode);
4172     ToCompute.reset(is_Computed);
4173     // if (ToCompute.test(ConeProperty::DefaultMode) && ToCompute.goals().none()) {
4174     //    ToCompute.reset(ConeProperty::DefaultMode);
4175     // }
4176 }
4177 
4178 //---------------------------------------------------------------------------
4179 
4180 template <typename Integer>
MakeSubAndQuot(const Matrix<Integer> & Gen,const Matrix<Integer> & Ker)4181 vector<Sublattice_Representation<Integer> > MakeSubAndQuot(const Matrix<Integer>& Gen, const Matrix<Integer>& Ker) {
4182     vector<Sublattice_Representation<Integer> > Result;
4183     Matrix<Integer> Help = Gen;
4184     Help.append(Ker);
4185     Sublattice_Representation<Integer> Sub(Help, true);
4186     Sublattice_Representation<Integer> Quot = Sub;
4187     if (Ker.nr_of_rows() > 0) {
4188         Matrix<Integer> HelpQuot = Sub.to_sublattice(Ker).kernel(false);  // kernel here to be interpreted as subspace of the dual
4189                                                                           // namely the linear forms vanishing on Ker
4190         Sublattice_Representation<Integer> SubToQuot(HelpQuot, true);     // sublattice of the dual
4191         Quot.compose_dual(SubToQuot);
4192     }
4193     Result.push_back(Sub);
4194     Result.push_back(Quot);
4195 
4196     return Result;
4197 }
4198 
4199 //---------------------------------------------------------------------------
4200 
4201 template <typename Integer>
4202 template <typename IntegerFC>
compute_dual_inner(ConeProperties & ToCompute)4203 void Cone<Integer>::compute_dual_inner(ConeProperties& ToCompute) {
4204 
4205 #ifdef NMZ_EXTENDED_TESTS
4206     if(!using_GMP<IntegerFC>() && test_arith_overflow_dual_mode)
4207         throw ArithmeticException(0);
4208 #endif
4209 
4210     bool do_only_Deg1_Elements = ToCompute.test(ConeProperty::Deg1Elements) && !ToCompute.test(ConeProperty::HilbertBasis);
4211 
4212     if (isComputed(ConeProperty::Generators) && SupportHyperplanes.nr_of_rows() == 0) {
4213         if (verbose) {
4214             verboseOutput() << "Computing support hyperplanes for the dual mode:" << endl;
4215         }
4216         ConeProperties Dualize;
4217         Dualize.set(ConeProperty::SupportHyperplanes);
4218         Dualize.set(ConeProperty::ExtremeRays);
4219         if (ToCompute.test(ConeProperty::KeepOrder) && dual_original_generators)
4220             Dualize.set(ConeProperty::KeepOrder);
4221         compute(Dualize);
4222     }
4223 
4224     bool do_extreme_rays_first = false;
4225     if (!isComputed(ConeProperty::ExtremeRays)) {
4226         if (do_only_Deg1_Elements && Grading.size() == 0)
4227             do_extreme_rays_first = true;
4228         else if ((do_only_Deg1_Elements || inhomogeneous) &&
4229                  (ToCompute.test(ConeProperty::NakedDual) || ToCompute.test(ConeProperty::ExtremeRays) ||
4230                   ToCompute.test(ConeProperty::SupportHyperplanes) || ToCompute.test(ConeProperty::Sublattice)))
4231             do_extreme_rays_first = true;
4232     }
4233 
4234     if (do_extreme_rays_first) {
4235         if (verbose) {
4236             verboseOutput() << "Computing extreme rays for the dual mode:" << endl;
4237         }
4238         compute_generators(ToCompute);  // computes extreme rays, but does not find grading !
4239     }
4240 
4241     if (do_only_Deg1_Elements && Grading.size()==0){
4242         if(Generators.nr_of_rows()>0){
4243             throw BadInputException("Need grading to compute degree 1 elements and cannot find one.");
4244         }
4245         else
4246             Grading=vector<Integer>(dim,0);
4247     }
4248 
4249 
4250     if (SupportHyperplanes.nr_of_rows() == 0 && !isComputed(ConeProperty::SupportHyperplanes)) {
4251         throw FatalException("Could not get SupportHyperplanes.");
4252     }
4253 
4254     Matrix<IntegerFC> Inequ_on_Ker;
4255     BasisChangePointed.convert_to_sublattice_dual(Inequ_on_Ker, SupportHyperplanes);
4256 
4257     vector<IntegerFC> Truncation;
4258     if (inhomogeneous) {
4259         BasisChangePointed.convert_to_sublattice_dual_no_div(Truncation, Dehomogenization);
4260     }
4261     if (do_only_Deg1_Elements) {
4262         // in this case the grading acts as truncation and it is a NEW inequality
4263         if(ToCompute.test(ConeProperty::NoGradingDenom))
4264             BasisChangePointed.convert_to_sublattice_dual_no_div(Truncation, Grading);
4265         else
4266             BasisChangePointed.convert_to_sublattice_dual(Truncation, Grading);
4267     }
4268 
4269     Cone_Dual_Mode<IntegerFC> ConeDM(Inequ_on_Ker, Truncation,
4270                                      ToCompute.test(ConeProperty::KeepOrder) && dual_original_generators);
4271     // Inequ_on_Ker is NOT const
4272     Inequ_on_Ker = Matrix<IntegerFC>(0, 0);  // destroy it
4273     ConeDM.verbose = verbose;
4274     ConeDM.inhomogeneous = inhomogeneous;
4275     ConeDM.do_only_Deg1_Elements = do_only_Deg1_Elements;
4276     if (isComputed(ConeProperty::Generators))
4277         BasisChangePointed.convert_to_sublattice(ConeDM.Generators, Generators);
4278     if (isComputed(ConeProperty::ExtremeRays))
4279         ConeDM.ExtremeRaysInd = ExtremeRaysIndicator;
4280     ConeDM.hilbert_basis_dual();
4281 
4282     if (!isComputed(ConeProperty::MaximalSubspace)) {
4283         BasisChangePointed.convert_from_sublattice(BasisMaxSubspace, ConeDM.BasisMaxSubspace);
4284         BasisMaxSubspace.standardize_basis();
4285         check_vanishing_of_grading_and_dehom();  // all this must be done here because to_sublattice may kill it
4286     }
4287 
4288     if (!isComputed(ConeProperty::Sublattice) || !isComputed(ConeProperty::MaximalSubspace)) {
4289         if (!(do_only_Deg1_Elements || inhomogeneous)) {
4290             // At this point we still have BasisChange==BasisChangePointed
4291             // now we can pass to a pointed full-dimensional cone
4292 
4293             vector<Sublattice_Representation<IntegerFC> > BothRepFC = MakeSubAndQuot(ConeDM.Generators, ConeDM.BasisMaxSubspace);
4294             if (!BothRepFC[0].IsIdentity())
4295                 BasisChange.compose(Sublattice_Representation<Integer>(BothRepFC[0]));
4296             setComputed(ConeProperty::Sublattice);
4297             if (!BothRepFC[1].IsIdentity())
4298                 BasisChangePointed.compose(Sublattice_Representation<Integer>(BothRepFC[1]));
4299             ConeDM.to_sublattice(BothRepFC[1]);
4300         }
4301     }
4302 
4303     setComputed(ConeProperty::MaximalSubspace);  // NOT EARLIER !!!!
4304 
4305     // create a Full_Cone out of ConeDM
4306     Full_Cone<IntegerFC> FC(ConeDM);
4307     FC.verbose = verbose;
4308     // Give extra data to FC
4309     if (Grading.size() > 0) {
4310         BasisChangePointed.convert_to_sublattice_dual(FC.Grading, Grading);
4311         if (isComputed(ConeProperty::Grading))
4312             FC.is_Computed.set(ConeProperty::Grading);
4313     }
4314     if (inhomogeneous)
4315         BasisChangePointed.convert_to_sublattice_dual_no_div(FC.Truncation, Dehomogenization);
4316     FC.do_class_group = ToCompute.test(ConeProperty::ClassGroup);
4317     FC.dual_mode();
4318     extract_data(FC, ToCompute);
4319 
4320     /* if(verbose){
4321             cout << "Emb" << endl;
4322             BasisChangePointed.getEmbeddingMatrix().pretty_print(cout);
4323             cout << "Proj" << endl;
4324             BasisChangePointed.getProjectionMatrix().pretty_print(cout);
4325             cout << "ProjKey" << endl;
4326             cout << BasisChangePointed.getProjectionKey();
4327             cout << "Hilb" << endl;
4328             HilbertBasis.pretty_print(cout);
4329             cout << "Supps " << endl;
4330             SupportHyperplanes.pretty_print(cout);
4331     }*/
4332 }
4333 
4334 #ifdef ENFNORMALIZ
4335 template <>
4336 template <typename IntegerFC>
compute_dual_inner(ConeProperties & ToCompute)4337 void Cone<renf_elem_class>::compute_dual_inner(ConeProperties& ToCompute) {
4338     assert(false);
4339 }
4340 #endif
4341 //---------------------------------------------------------------------------
4342 
4343 template <typename Integer>
compute_primary_multiplicity()4344 Integer Cone<Integer>::compute_primary_multiplicity() {
4345     if (change_integer_type) {
4346         try {
4347             return compute_primary_multiplicity_inner<MachineInteger>();
4348         } catch (const ArithmeticException& e) {
4349             if (verbose) {
4350                 verboseOutput() << e.what() << endl;
4351                 verboseOutput() << "Restarting with a bigger type." << endl;
4352             }
4353             change_integer_type = false;
4354         }
4355     }
4356     return compute_primary_multiplicity_inner<Integer>();
4357 }
4358 
4359 //---------------------------------------------------------------------------
4360 
4361 template <typename Integer>
4362 template <typename IntegerFC>
compute_primary_multiplicity_inner()4363 Integer Cone<Integer>::compute_primary_multiplicity_inner() {
4364     Matrix<IntegerFC> Ideal(0, dim - 1);
4365     vector<IntegerFC> help(dim - 1);
4366     for (size_t i = 0; i < Generators.nr_of_rows(); ++i) {  // select ideal generators
4367         if (Generators[i][dim - 1] == 1) {
4368             for (size_t j = 0; j < dim - 1; ++j)
4369                 convert(help[j], Generators[i][j]);
4370             Ideal.append(help);
4371         }
4372     }
4373     Full_Cone<IntegerFC> IdCone(Ideal, false);
4374     IdCone.do_bottom_dec = true;
4375     IdCone.do_determinants = true;
4376     IdCone.compute();
4377     return convertTo<Integer>(IdCone.detSum);
4378 }
4379 
4380 //---------------------------------------------------------------------------
4381 
4382 // This function creates convex hull data from precomputed support hyperplanes and extreme rays
4383 // so that these can be used in interactive mode for the modification of the originally constructed cone
4384 // In principle it works like extract_convex_hull_data below.
4385 template <typename Integer>
create_convex_hull_data()4386 void Cone<Integer>::create_convex_hull_data() {
4387 
4388     ConvHullData.is_primal=true;
4389 
4390     ConvHullData.SLR = BasisChangePointed;
4391     ConvHullData.nr_threads = omp_get_max_threads();
4392     ConvHullData.HypCounter=vector<size_t>(ConvHullData.nr_threads);
4393     for(int i=0;i<ConvHullData.nr_threads;++i)
4394         ConvHullData.HypCounter[i]=i+1;
4395     ConvHullData.old_nr_supp_hyps=SupportHyperplanes.nr_of_rows();
4396 
4397     size_t nr_extreme_rays = ExtremeRays.nr_of_rows();
4398     // no better idea
4399     ConvHullData.Comparisons.resize(nr_extreme_rays);
4400     ConvHullData.nrTotalComparisons = 0;
4401 
4402     ConvHullData.in_triang = vector<bool>(nr_extreme_rays, true);
4403     ConvHullData.GensInCone = identity_key(nr_extreme_rays);
4404     ConvHullData.nrGensInCone = nr_extreme_rays;
4405 
4406     ConvHullData.Generators=ExtremeRays;
4407 
4408     ConvHullData.Facets.clear();
4409 
4410     size_t rank=ExtremeRays.rank();
4411 
4412     for (auto& Fac : SupportHyperplanes.get_elements()) {
4413         FACETDATA<Integer> Ret;
4414         Ret.Hyp=Fac;
4415         Ret.GenInHyp.resize(nr_extreme_rays);
4416         size_t nr_gens_in_hyp=0;
4417         for (size_t i = 0; i < nr_extreme_rays; ++i) {
4418             Integer p=v_scalar_product(Fac,ConvHullData.Generators[i]);
4419             if(p<0)
4420                 throw BadInputException("Incompatible precomputed data: wextreme rays and support hyperplanes inconsitent");
4421             Ret.GenInHyp[i]=0;
4422             if(p==0){
4423                 Ret.GenInHyp[i]=1;
4424                 nr_gens_in_hyp++;
4425             }
4426         }
4427 
4428         Ret.BornAt = 0;  // no better choice
4429         Ret.Mother = 0;  // ditto
4430         Ret.Ident = ConvHullData.HypCounter[0];
4431         ConvHullData.HypCounter[0]+=ConvHullData.nr_threads; // we use only residue class 0 mod nr_threads
4432         Ret.simplicial = (nr_gens_in_hyp==rank-1);
4433 
4434         ConvHullData.Facets.push_back(Ret);
4435     }
4436 }
4437 
4438 //---------------------------------------------------------------------------
4439 
4440 template <typename Integer>
4441 template <typename IntegerFC>
extract_convex_hull_data(Full_Cone<IntegerFC> & FC,bool primal)4442 void Cone<Integer>::extract_convex_hull_data(Full_Cone<IntegerFC>& FC, bool primal) {
4443     ConvHullData.SLR = BasisChangePointed;
4444     ConvHullData.nr_threads = omp_get_max_threads();
4445 
4446     ConvHullData.is_primal = primal;
4447     // ConvHullData.Generators=Generators;
4448     swap(ConvHullData.HypCounter, FC.HypCounter);
4449     // swap(ConvHullData.in_triang,FC.in_triang);
4450     // swap(ConvHullData.GensInCone,FC.GensInCone);
4451     // ConvHullData.nrGensInCone=FC.nrGensInCone;
4452     swap(ConvHullData.Comparisons, FC.Comparisons);
4453     ConvHullData.nrTotalComparisons = FC.nrTotalComparisons;
4454     ConvHullData.old_nr_supp_hyps = FC.old_nr_supp_hyps;
4455 
4456     ConvHullData.Generators = Matrix<Integer>(0, dim);
4457     for (size_t i = 0; i < FC.nr_gen; ++i) {
4458         if (FC.Extreme_Rays_Ind[i]) {
4459             vector<Integer> v;
4460             if (primal)
4461                 BasisChangePointed.convert_from_sublattice(v, FC.getGenerators()[i]);
4462             else
4463                 BasisChangePointed.convert_from_sublattice_dual(v, FC.getGenerators()[i]);
4464             ConvHullData.Generators.append(v);
4465         }
4466     }
4467 
4468     size_t nr_extreme_rays = ConvHullData.Generators.nr_of_rows();
4469 
4470     ConvHullData.in_triang = vector<bool>(nr_extreme_rays, true);
4471     ConvHullData.GensInCone = identity_key(nr_extreme_rays);
4472     ConvHullData.nrGensInCone = nr_extreme_rays;
4473 
4474     ConvHullData.Facets.clear();
4475 
4476     for (const auto& Fac : FC.Facets) {
4477         FACETDATA<Integer> Ret;
4478         if (primal)
4479             BasisChangePointed.convert_from_sublattice_dual(Ret.Hyp, Fac.Hyp);
4480         else
4481             BasisChangePointed.convert_from_sublattice(Ret.Hyp, Fac.Hyp);
4482 
4483         // swap(Ret.GenInHyp,Fac.GenInHyp);
4484         // convert(Ret.ValNewGen,Fac.ValNewGen);
4485         Ret.GenInHyp.resize(nr_extreme_rays);
4486         size_t j = 0;
4487         for (size_t i = 0; i < FC.nr_gen; ++i) {
4488             if (FC.Extreme_Rays_Ind[i]) {
4489                 Ret.GenInHyp[j] = Fac.GenInHyp[i];
4490                 j++;
4491             }
4492         }
4493 
4494         Ret.BornAt = 0;  // no better choice
4495         Ret.Mother = 0;  // ditto
4496         Ret.Ident = Fac.Ident;
4497         // Ret.is_positive_on_all_original_gens = Fac.is_positive_on_all_original_gens;
4498         // Ret.is_negative_on_some_original_gen = Fac.is_negative_on_some_original_gen;
4499         Ret.simplicial = Fac.simplicial;
4500 
4501         ConvHullData.Facets.push_back(Ret);
4502     }
4503 
4504     /* FC.getGenerators().pretty_print(cout);
4505     cout << "-----------" << endl;
4506     ConvHullData.Generators.pretty_print(cout);
4507     cout << "-----------" << endl;*/
4508 }
4509 
4510 template <typename Integer>
compute_recession_rank()4511 void Cone<Integer>::compute_recession_rank() {
4512     if(isComputed(ConeProperty::RecessionRank) || !inhomogeneous)
4513         return;
4514     compute(ConeProperty::ExtremeRays);
4515     vector<key_t> level0key;
4516     Matrix<Integer> Help=BasisChangePointed.to_sublattice(ExtremeRays);
4517     vector<Integer> HelpDehom=BasisChangePointed.to_sublattice_dual(Dehomogenization);
4518     for(size_t i=0; i < Help.nr_of_rows(); ++i){
4519         if(v_scalar_product(Help[i],HelpDehom)==0)
4520             level0key.push_back(i);
4521     }
4522     size_t pointed_recession_rank = Help.submatrix(level0key).rank();
4523     if (!isComputed(ConeProperty::MaximalSubspace))
4524         compute(ConeProperty::MaximalSubspace);
4525     recession_rank = pointed_recession_rank + BasisMaxSubspace.nr_of_rows();
4526     setComputed(ConeProperty::RecessionRank);
4527 }
4528 
4529 template <typename Integer>
compute_affine_dim_and_recession_rank()4530 void Cone<Integer>::compute_affine_dim_and_recession_rank() {
4531 
4532     if((isComputed(ConeProperty::AffineDim) && isComputed(ConeProperty::RecessionRank)) || !inhomogeneous)
4533         return;
4534 
4535     if (!isComputed(ConeProperty::RecessionRank))
4536         compute_recession_rank();
4537 
4538     if (get_rank_internal() == recession_rank) {
4539         affine_dim = -1;
4540     }
4541     else {
4542         affine_dim = get_rank_internal() - 1;
4543     }
4544     setComputed(ConeProperty::AffineDim);
4545 }
4546 
4547 //---------------------------------------------------------------------------
4548 
4549 template <typename Integer>
4550 template <typename IntegerFC>
extract_data(Full_Cone<IntegerFC> & FC,ConeProperties & ToCompute)4551 void Cone<Integer>::extract_data(Full_Cone<IntegerFC>& FC, ConeProperties& ToCompute) {
4552     // this function extracts ALL available data from the Full_Cone
4553     // even if it was in Cone already <- this may change
4554     // it is possible to delete the data in Full_Cone after extracting it
4555 
4556     if (verbose) {
4557         verboseOutput() << "transforming data..." << flush;
4558     }
4559 
4560     // It is important to extract the generators from the full cone.
4561     // The generators extracted from the full cone are the "purified" versions of
4562     // the generators with which the full cone was constructed. Since the order
4563     // can change, ExtremeRays is reset. Will be set again below.
4564     if (FC.isComputed(ConeProperty::Generators)) {
4565         BasisChangePointed.convert_from_sublattice(Generators, FC.getGenerators());
4566         setComputed(ConeProperty::Generators);
4567         ExtremeRaysIndicator.resize(0);
4568         is_Computed.reset(ConeProperty::ExtremeRays);
4569     }
4570 
4571     if (keep_convex_hull_data) {
4572         extract_convex_hull_data(FC, true);
4573     }
4574 
4575     if (FC.isComputed(ConeProperty::IsPointed) && !isComputed(ConeProperty::IsPointed)) {
4576         pointed = FC.isPointed();
4577         if (pointed)
4578             setComputed(ConeProperty::MaximalSubspace);
4579         setComputed(ConeProperty::IsPointed);
4580     }
4581 
4582     if(FC.isComputed(ConeProperty::IsEmptySemiOpen)){
4583         empty_semiopen = false;
4584         if(FC.index_covering_face < ExcludedFaces.nr_of_rows()){
4585             empty_semiopen = true;
4586             CoveringFace = ExcludedFaces[FC.index_covering_face];
4587             setComputed(ConeProperty::CoveringFace);
4588         }
4589         setComputed(ConeProperty::IsEmptySemiOpen);
4590     }
4591 
4592     Integer local_grading_denom;
4593     if(is_Computed.goals_using_grading(inhomogeneous).any()) // in this case we do not pull
4594         local_grading_denom = GradingDenom;                  // the grading from FC
4595     else
4596         local_grading_denom = 1;
4597 
4598     if (FC.isComputed(ConeProperty::Grading) && !using_renf<Integer>() && is_Computed.goals_using_grading(inhomogeneous).none()) {
4599         if (BasisChangePointed.getRank() != 0) {
4600             vector<Integer> test_grading_1, test_grading_2;
4601             if (Grading.size() == 0)  // grading is implicit, get it from FC
4602                 BasisChangePointed.convert_from_sublattice_dual(test_grading_1, FC.getGrading());
4603             else
4604                 test_grading_1 = Grading;
4605             test_grading_2 = BasisChangePointed.to_sublattice_dual_no_div(test_grading_1);
4606             local_grading_denom = v_gcd(test_grading_2);
4607         }
4608 
4609         if (Grading.size() == 0) {
4610             BasisChangePointed.convert_from_sublattice_dual(Grading, FC.getGrading());
4611             if (local_grading_denom > 1 && ToCompute.test(ConeProperty::NoGradingDenom))
4612                 throw BadInputException("Grading denominator of implicit grading > 1 not allowed with NoGradingDenom.");
4613         }
4614 
4615         setComputed(ConeProperty::Grading);
4616         setWeights();
4617 
4618         // set denominator of Grading
4619         GradingDenom = 1;  // should have this value already, but to be on the safe sisde
4620         if (!ToCompute.test(ConeProperty::NoGradingDenom))
4621             GradingDenom = local_grading_denom;
4622         setComputed(ConeProperty::GradingDenom);
4623     }
4624 
4625     if (FC.isComputed(ConeProperty::ModuleGeneratorsOverOriginalMonoid)) {  // must precede extreme rays
4626         BasisChangePointed.convert_from_sublattice(ModuleGeneratorsOverOriginalMonoid,
4627                                                    FC.getModuleGeneratorsOverOriginalMonoid());
4628         ModuleGeneratorsOverOriginalMonoid.sort_by_weights(WeightsGrad, GradAbs);
4629         setComputed(ConeProperty::ModuleGeneratorsOverOriginalMonoid);
4630     }
4631 
4632     // Important: must be done after ModuleGeneratorsOverOriginalMonoid because in this case
4633     // generators may not be primitive or can contain duplicates genereating the same ray
4634     if (FC.isComputed(ConeProperty::ExtremeRays) ) {
4635         set_extreme_rays(FC.getExtremeRays());
4636     }
4637 
4638     if (FC.isComputed(ConeProperty::SupportHyperplanes)) {
4639         /* if (inhomogeneous) {
4640             // remove irrelevant support hyperplane 0 ... 0 1
4641             vector<IntegerFC> irr_hyp_subl;
4642             BasisChangePointed.convert_to_sublattice_dual(irr_hyp_subl, Dehomogenization);
4643             FC.Support_Hyperplanes.remove_row(irr_hyp_subl);
4644         } */
4645         // BasisChangePointed.convert_from_sublattice_dual(SupportHyperplanes, FC.getSupportHyperplanes());
4646         extract_supphyps(FC, SupportHyperplanes);
4647         if (using_renf<Integer>())
4648             SupportHyperplanes.standardize_rows();
4649         norm_dehomogenization(FC.dim);
4650         SupportHyperplanes.sort_lex();
4651         setComputed(ConeProperty::SupportHyperplanes);
4652         addition_constraints_allowed=true;
4653     }
4654     if (FC.isComputed(ConeProperty::TriangulationSize)  && !FC.isComputed(ConeProperty::PullingTriangulation)) {
4655         TriangulationSize = FC.totalNrSimplices;
4656         triangulation_is_nested = FC.triangulation_is_nested;
4657         triangulation_is_partial = FC.triangulation_is_partial;
4658         setComputed(ConeProperty::TriangulationSize);
4659         setComputed(ConeProperty::IsTriangulationPartial);
4660         setComputed(ConeProperty::IsTriangulationNested);
4661     }
4662     if (FC.isComputed(ConeProperty::TriangulationDetSum) && !FC.isComputed(ConeProperty::PullingTriangulation) ) {
4663         convert(TriangulationDetSum, FC.detSum);
4664         setComputed(ConeProperty::TriangulationDetSum);
4665     }
4666 
4667     if (FC.isComputed(ConeProperty::Triangulation)) {
4668 
4669         is_Computed.reset(all_triangulations()); // must reset these friends
4670                                                     // when the basic triangulation
4671         is_Computed.reset(ConeProperty::UnimodularTriangulation); // is recomputed
4672         Triangulation.first.clear();
4673 
4674         BasisChangePointed.convert_from_sublattice(BasicTriangulation.second, FC.getGenerators());
4675 
4676         size_t tri_size = FC.Triangulation.size();
4677         FC.Triangulation.sort(compareKeys<IntegerFC>);  // necessary to make triangulation unique
4678         BasicTriangulation.first.resize(tri_size);
4679         SHORTSIMPLEX<IntegerFC> simp;
4680         for (size_t i = 0; i < tri_size; ++i) {
4681             simp = FC.Triangulation.front();
4682             BasicTriangulation.first[i].key.swap(simp.key);
4683             if (FC.isComputed(ConeProperty::TriangulationDetSum))
4684                 convert(BasicTriangulation.first[i].vol, simp.vol);
4685             else
4686                 BasicTriangulation.first[i].vol = 0;
4687             if (FC.isComputed(ConeProperty::ConeDecomposition))
4688                 BasicTriangulation.first[i].Excluded.swap(simp.Excluded);
4689             FC.Triangulation.pop_front();
4690         }
4691         if (FC.isComputed(ConeProperty::ConeDecomposition))
4692             setComputed(ConeProperty::ConeDecomposition);
4693 
4694         setComputed(ConeProperty::BasicTriangulation);
4695 
4696         if(ToCompute.test(ConeProperty::PlacingTriangulation)){
4697             setComputed(ConeProperty::PlacingTriangulation);
4698             Triangulation = BasicTriangulation;
4699         }
4700     }
4701 
4702     if (FC.isComputed(ConeProperty::StanleyDec)) {
4703         BasicStanleyDec.first.clear();
4704         BasicStanleyDec.first.splice(BasicStanleyDec.first.begin(), FC.StanleyDec);
4705         setComputed(ConeProperty::BasicStanleyDec);
4706         BasisChangePointed.convert_from_sublattice(BasicStanleyDec.second, FC.getGenerators());
4707     }
4708 
4709     if (FC.isComputed(ConeProperty::InclusionExclusionData)) {
4710         InExData.clear();
4711         InExData.reserve(FC.InExCollect.size());
4712         vector<key_t> key;
4713         for (const auto& F : FC.InExCollect) {
4714             key.clear();
4715             for (size_t i = 0; i < FC.nr_gen; ++i) {
4716                 if (F.first.test(i)) {
4717                     key.push_back(i);
4718                 }
4719             }
4720             InExData.push_back(make_pair(key, F.second));
4721         }
4722         setComputed(ConeProperty::InclusionExclusionData);
4723     }
4724     if (FC.isComputed(ConeProperty::RecessionRank) && isComputed(ConeProperty::MaximalSubspace)) {
4725         recession_rank = FC.level0_dim + BasisMaxSubspace.nr_of_rows();
4726         setComputed(ConeProperty::RecessionRank);
4727         if(isComputed(ConeProperty::Sublattice))
4728             compute_affine_dim_and_recession_rank();
4729     }
4730 
4731     if (FC.isComputed(ConeProperty::ModuleRank)) {
4732         module_rank = FC.getModuleRank();
4733         setComputed(ConeProperty::ModuleRank);
4734     }
4735 
4736     // It would be correct to extract the multiülicity also from FC with the pulling triangulation.
4737     // However, we insist that no additional information is computed from it to avoid confusion.
4738     if (FC.isComputed(ConeProperty::Multiplicity) && !using_renf<Integer>()  && !FC.isComputed(ConeProperty::PullingTriangulation)) {
4739         if (!inhomogeneous) {
4740             multiplicity = FC.getMultiplicity();
4741             setComputed(ConeProperty::Multiplicity);
4742         }
4743         else if (FC.isComputed(ConeProperty::ModuleRank)) {
4744             multiplicity = FC.getMultiplicity() * static_cast<unsigned long>(module_rank);
4745             setComputed(ConeProperty::Multiplicity);
4746         }
4747     }
4748 
4749 #ifdef ENFNORMALIZ
4750     if (FC.isComputed(ConeProperty::Multiplicity) && using_renf<Integer>()) {
4751         renf_volume = FC.renf_multiplicity;
4752         // setComputed(ConeProperty::Multiplicity);
4753         setComputed(ConeProperty::Volume);
4754         setComputed(ConeProperty::RenfVolume);
4755         euclidean_volume = static_cast<double>(renf_volume);
4756         for (size_t i = 1; i < dim; ++i)
4757             euclidean_volume /= i;
4758         euclidean_volume *= euclidean_height;
4759 
4760         setComputed(ConeProperty::EuclideanVolume);
4761     }
4762 #endif
4763 
4764     if (FC.isComputed(ConeProperty::WitnessNotIntegrallyClosed)) {
4765         BasisChangePointed.convert_from_sublattice(WitnessNotIntegrallyClosed, FC.Witness);
4766         setComputed(ConeProperty::WitnessNotIntegrallyClosed);
4767         integrally_closed = false;
4768         setComputed(ConeProperty::IsIntegrallyClosed);
4769     }
4770     if (FC.isComputed(ConeProperty::HilbertBasis)) {
4771         if (inhomogeneous) {
4772             // separate (capped) Hilbert basis to the Hilbert basis of the level 0 cone
4773             // and the module generators in level 1
4774             HilbertBasis = Matrix<Integer>(0, dim);
4775             ModuleGenerators = Matrix<Integer>(0, dim);
4776             typename list<vector<IntegerFC> >::const_iterator FCHB(FC.Hilbert_Basis.begin());
4777             vector<Integer> tmp;
4778             for (; FCHB != FC.Hilbert_Basis.end(); ++FCHB) {
4779                 INTERRUPT_COMPUTATION_BY_EXCEPTION
4780 
4781                 BasisChangePointed.convert_from_sublattice(tmp, *FCHB);
4782                 if (v_scalar_product(tmp, Dehomogenization) == 0) {  // Hilbert basis element of the cone at level 0
4783                     HilbertBasis.append(tmp);
4784                 }
4785                 else {  // module generator
4786                     ModuleGenerators.append(tmp);
4787                 }
4788             }
4789             ModuleGenerators.sort_by_weights(WeightsGrad, GradAbs);
4790             setComputed(ConeProperty::ModuleGenerators);
4791             number_lattice_points = ModuleGenerators.nr_of_rows();
4792             setComputed(ConeProperty::NumberLatticePoints);
4793         }
4794         else {  // homogeneous
4795             HilbertBasis = Matrix<Integer>(0, dim);
4796             typename list<vector<IntegerFC> >::const_iterator FCHB(FC.Hilbert_Basis.begin());
4797             vector<Integer> tmp;
4798             for (; FCHB != FC.Hilbert_Basis.end(); ++FCHB) {
4799                 BasisChangePointed.convert_from_sublattice(tmp, *FCHB);
4800                 HilbertBasis.append(tmp);
4801             }
4802         }
4803         HilbertBasis.sort_by_weights(WeightsGrad, GradAbs);
4804         setComputed(ConeProperty::HilbertBasis);
4805     }
4806 
4807     if (FC.isComputed(ConeProperty::Deg1Elements)) {
4808         Deg1Elements = Matrix<Integer>(0, dim);
4809         if (local_grading_denom == GradingDenom) {
4810             typename list<vector<IntegerFC> >::const_iterator DFC(FC.Deg1_Elements.begin());
4811             vector<Integer> tmp;
4812             for (; DFC != FC.Deg1_Elements.end(); ++DFC) {
4813                 INTERRUPT_COMPUTATION_BY_EXCEPTION
4814 
4815                 BasisChangePointed.convert_from_sublattice(tmp, *DFC);
4816                 Deg1Elements.append(tmp);
4817             }
4818             Deg1Elements.sort_by_weights(WeightsGrad, GradAbs);
4819         }
4820         setComputed(ConeProperty::Deg1Elements);
4821         number_lattice_points = Deg1Elements.nr_of_rows();
4822         setComputed(ConeProperty::NumberLatticePoints);
4823     }
4824 
4825     if (FC.isComputed(ConeProperty::HilbertSeries)) {
4826         long save_nr_coeff_quasipol = HSeries.get_nr_coeff_quasipol();  // Full_Cone does not compute the quasipolynomial
4827         long save_expansion_degree = HSeries.get_expansion_degree();    // or the expansion
4828         HSeries = FC.Hilbert_Series;
4829         HSeries.set_nr_coeff_quasipol(save_nr_coeff_quasipol);
4830         HSeries.set_expansion_degree(save_expansion_degree);
4831         setComputed(ConeProperty::HilbertSeries);
4832         // setComputed(ConeProperty::ExplicitHilbertSeries);
4833     }
4834     if (FC.isComputed(ConeProperty::HSOP)) {
4835         setComputed(ConeProperty::HSOP);
4836     }
4837     if (FC.isComputed(ConeProperty::IsDeg1ExtremeRays)) {
4838         deg1_extreme_rays = FC.isDeg1ExtremeRays();
4839         setComputed(ConeProperty::IsDeg1ExtremeRays);
4840     }
4841     if (FC.isComputed(ConeProperty::ExcludedFaces)) {
4842         BasisChangePointed.convert_from_sublattice_dual(ExcludedFaces, FC.getExcludedFaces());
4843         ExcludedFaces.sort_lex();
4844         setComputed(ConeProperty::ExcludedFaces);
4845     }
4846 
4847     if (FC.isComputed(ConeProperty::IsDeg1HilbertBasis)) {
4848         deg1_hilbert_basis = FC.isDeg1HilbertBasis();
4849         setComputed(ConeProperty::IsDeg1HilbertBasis);
4850     }
4851     if (FC.isComputed(ConeProperty::ClassGroup)) {
4852         convert(ClassGroup, FC.ClassGroup);
4853         setComputed(ConeProperty::ClassGroup);
4854     }
4855 
4856     if (FC.isComputed(ConeProperty::Automorphisms)) {
4857 
4858         extract_automorphisms(FC.Automs, true); // true = must transform
4859 
4860         if (ToCompute.test(ConeProperty::Automorphisms))
4861             setComputed(ConeProperty::Automorphisms);
4862         if (ToCompute.test(ConeProperty::RationalAutomorphisms))
4863             setComputed(ConeProperty::RationalAutomorphisms);
4864         /* if (FC.isComputed(ConeProperty::ExploitAutomsVectors))
4865             setComputed(ConeProperty::ExploitAutomsVectors); */
4866     }
4867 
4868     check_integrally_closed(ToCompute);
4869 
4870     if (verbose) {
4871         verboseOutput() << " done." << endl;
4872     }
4873 }
4874 
4875 //---------------------------------------------------------------------------
4876 template <typename Integer>
extract_subsets(const vector<vector<key_t>> & FC_Subsets,size_t max_index,const vector<key_t> & Key)4877 vector<vector<key_t> > Cone<Integer>::extract_subsets(const vector<vector<key_t> >& FC_Subsets,
4878                                                       size_t max_index,
4879                                                       const vector<key_t>& Key) {
4880     // Key is an injective map from [0,m-1] to [0,max_index-1];
4881     // Inv is its partial inverse, defined on Image(Key)
4882     // We assume that an indifidual subset of  [0,max_index-1] that has nonempty intersection
4883     // with Image(Key) is contained in Image(Key)
4884     // The nonempty intersections are mapped to subsets of [0,m-1] by Inv
4885     //
4886     // This funnction does not use the class Cone; could be in vector_operations
4887     //
4888 
4889     vector<vector<key_t> > C_Subsets;
4890     if (Key.empty())
4891         return C_Subsets;
4892 
4893     vector<key_t> Inv(max_index);
4894     for (size_t i = 0; i < Key.size(); ++i)
4895         Inv[Key[i]] = i;
4896 
4897     for (const auto& FC_Subset : FC_Subsets) {
4898         bool nonempty = false;
4899         for (unsigned int j : Key) {  // testing nonempty intersection = containment by assumption
4900             if (j == FC_Subset[0]) {
4901                 nonempty = true;
4902                 break;
4903             }
4904         }
4905         if (!nonempty)
4906             continue;
4907         vector<key_t> transf_subset(FC_Subset.size());
4908         for (size_t j = 0; j < FC_Subset.size(); ++j) {
4909             transf_subset[j] = Inv[FC_Subset[j]];
4910         }
4911         C_Subsets.push_back(transf_subset);
4912     }
4913     return C_Subsets;
4914 }
4915 
4916 //---------------------------------------------------------------------------
4917 template <typename Integer>
4918 template <typename IntegerFC>
extract_permutations(const vector<vector<key_t>> & FC_Permutations,Matrix<IntegerFC> & FC_Vectors,const Matrix<Integer> & ConeVectors,bool primal,vector<key_t> & Key,const bool must_transform)4919 vector<vector<key_t> > Cone<Integer>::extract_permutations(const vector<vector<key_t> >& FC_Permutations,
4920                                                            Matrix<IntegerFC>& FC_Vectors,
4921                                                            const Matrix<Integer>& ConeVectors,
4922                                                            bool primal,
4923                                                            vector<key_t>& Key,
4924                                                            const bool must_transform) {
4925     // Key has the same meaning as in extract_subsets,
4926     // but is computed by searching the properly transformed vectors of ConeVectors in FC_Vectors: ConeVector[i] =
4927     // FC_Vector[Key[i]] It is assumed that each permutation in FC_Permutations can be restricted to Image(Key) The induced
4928     // permutations on [0,m-1] (m=size(Key)) are computed.
4929 
4930     if (using_renf<Integer>()) {
4931         for (size_t i = 0; i < FC_Vectors.nr_of_rows(); ++i)
4932             v_standardize(FC_Vectors[i]);
4933     }
4934 
4935     map<vector<IntegerFC>, key_t> VectorsRef;
4936     for (size_t i = 0; i < FC_Vectors.nr_of_rows(); ++i) {
4937         VectorsRef[FC_Vectors[i]] = i;
4938     }
4939     Key.resize(ConeVectors.nr_of_rows());
4940 
4941     /*cout << "--------------" << endl;
4942     FC_Vectors.pretty_print(cout);
4943     cout << "--------------" << endl;
4944     ConeVectors.pretty_print(cout);
4945     cout << "=============" << endl;*/
4946 
4947     for (size_t i = 0; i < ConeVectors.nr_of_rows(); ++i) {
4948         vector<IntegerFC> search;
4949         if(must_transform){
4950             if (primal)
4951                 BasisChangePointed.convert_to_sublattice(search, ConeVectors[i]);
4952             else
4953                 BasisChangePointed.convert_to_sublattice_dual(search, ConeVectors[i]);
4954         }
4955         else{
4956             if (primal)
4957                 convert(search,ConeVectors[i]);
4958             else
4959                 convert(search,ConeVectors[i]);
4960         }
4961         if (using_renf<Integer>()) {
4962             v_standardize(search);
4963         }
4964         auto E = VectorsRef.find(search);
4965         assert(E != VectorsRef.end());
4966         Key[i] = E->second;
4967     }
4968 
4969     vector<vector<key_t> > ConePermutations;
4970     for (const auto& FC_Permutation : FC_Permutations) {
4971         ConePermutations.push_back(conjugate_perm(FC_Permutation, Key));
4972     }
4973     return ConePermutations;
4974 }
4975 
4976 //---------------------------------------------------------------------------
4977 template <typename Integer>
4978 template <typename IntegerFC>
extract_supphyps(Full_Cone<IntegerFC> & FC,Matrix<Integer> & ret,bool dual)4979 void Cone<Integer>::extract_supphyps(Full_Cone<IntegerFC>& FC, Matrix<Integer>& ret, bool dual) {
4980     if (dual)
4981         BasisChangePointed.convert_from_sublattice_dual(ret, FC.getSupportHyperplanes());
4982     else
4983         BasisChangePointed.convert_from_sublattice(ret, FC.getSupportHyperplanes());
4984 }
4985 
4986 template <typename Integer>
extract_supphyps(Full_Cone<Integer> & FC,Matrix<Integer> & ret,bool dual)4987 void Cone<Integer>::extract_supphyps(Full_Cone<Integer>& FC, Matrix<Integer>& ret, bool dual) {
4988     if (dual) {
4989         if (BasisChangePointed.IsIdentity())
4990             swap(ret, FC.Support_Hyperplanes);
4991         else
4992             ret = BasisChangePointed.from_sublattice_dual(FC.getSupportHyperplanes());
4993     }
4994     else {
4995         if (BasisChangePointed.IsIdentity())
4996             swap(ret, FC.Support_Hyperplanes);
4997         else
4998             ret = BasisChangePointed.from_sublattice(FC.getSupportHyperplanes());
4999     }
5000 }
5001 
5002 template <typename Integer>
norm_dehomogenization(size_t FC_dim)5003 void Cone<Integer>::norm_dehomogenization(size_t FC_dim) {
5004     if (inhomogeneous && FC_dim < dim) {  // make inequality for the inhomogeneous variable appear as dehomogenization
5005         vector<Integer> dehom_restricted = BasisChangePointed.to_sublattice_dual(Dehomogenization);
5006         if (using_renf<Integer>())
5007             v_standardize(dehom_restricted);
5008         for (size_t i = 0; i < SupportHyperplanes.nr_of_rows(); ++i) {
5009             vector<Integer> test = BasisChangePointed.to_sublattice_dual(SupportHyperplanes[i]);
5010             if (using_renf<Integer>())
5011                 v_standardize(test);
5012             if (dehom_restricted == test) {
5013                 SupportHyperplanes[i] = Dehomogenization;
5014                 break;
5015             }
5016         }
5017     }
5018 }
5019 
5020 //---------------------------------------------------------------------------
5021 
5022 template <typename Integer>
check_integrally_closed(const ConeProperties & ToCompute)5023 void Cone<Integer>::check_integrally_closed(const ConeProperties& ToCompute) {
5024 
5025     if (!isComputed(ConeProperty::OriginalMonoidGenerators) || inhomogeneous)
5026         return;
5027 
5028     if(isComputed(ConeProperty::IsIntegrallyClosed) && !ToCompute.test(ConeProperty::WitnessNotIntegrallyClosed))
5029         return;
5030 
5031     if(!ToCompute.test(ConeProperty::IsIntegrallyClosed) && !isComputed(ConeProperty::HilbertBasis)){
5032         return;
5033     }
5034 
5035     if(!isComputed(ConeProperty::IsIntegrallyClosed)){
5036         unit_group_index = 1;
5037         if (BasisMaxSubspace.nr_of_rows() > 0)
5038             compute_unit_group_index();
5039         setComputed(ConeProperty::UnitGroupIndex);
5040 
5041         if (internal_index != 1 || unit_group_index != 1){
5042             integrally_closed = false;
5043             setComputed(ConeProperty::IsIntegrallyClosed);
5044             return;
5045         }
5046     }
5047 
5048     if (!isComputed(ConeProperty::HilbertBasis))
5049         return;
5050 
5051     if (HilbertBasis.nr_of_rows() > InputGenerators.nr_of_rows()) {
5052         integrally_closed = false;
5053         setComputed(ConeProperty::IsIntegrallyClosed);
5054         if(!ToCompute.test(ConeProperty::WitnessNotIntegrallyClosed))
5055             return;
5056     }
5057     find_witness(ToCompute);
5058     setComputed(ConeProperty::IsIntegrallyClosed);
5059 }
5060 
5061 //---------------------------------------------------------------------------
5062 
5063 template <typename Integer>
compute_unit_group_index()5064 void Cone<Integer>::compute_unit_group_index() {
5065     assert(isComputed(ConeProperty::MaximalSubspace));
5066     // we want to compute in the maximal linear subspace
5067     Sublattice_Representation<Integer> Sub(BasisMaxSubspace, true);
5068     Matrix<Integer> origens_in_subspace(0, dim);
5069 
5070     // we must collect all original generators that lie in the maximal subspace
5071 
5072     for (size_t i = 0; i < InputGenerators.nr_of_rows(); ++i) {
5073         size_t j;
5074         for (j = 0; j < SupportHyperplanes.nr_of_rows(); ++j) {
5075             if (v_scalar_product(InputGenerators[i], SupportHyperplanes[j]) != 0)
5076                 break;
5077         }
5078         if (j == SupportHyperplanes.nr_of_rows())
5079             origens_in_subspace.append(InputGenerators[i]);
5080     }
5081     Matrix<Integer> M = Sub.to_sublattice(origens_in_subspace);
5082     unit_group_index = M.full_rank_index();
5083     // cout << "Unit group index " << unit_group_index;
5084 }
5085 
5086 //---------------------------------------------------------------------------
5087 
5088 template <typename Integer>
find_witness(const ConeProperties & ToCompute)5089 void Cone<Integer>::find_witness(const ConeProperties& ToCompute) {
5090     if (!isComputed(ConeProperty::OriginalMonoidGenerators) || inhomogeneous) {
5091         // no original monoid defined
5092         throw NotComputableException(ConeProperties(ConeProperty::WitnessNotIntegrallyClosed));
5093     }
5094     if (isComputed(ConeProperty::IsIntegrallyClosed) && integrally_closed) {
5095         // original monoid is integrally closed
5096         throw NotComputableException(ConeProperties(ConeProperty::WitnessNotIntegrallyClosed));
5097     }
5098     if (isComputed(ConeProperty::WitnessNotIntegrallyClosed) || !isComputed(ConeProperty::HilbertBasis))
5099         return;
5100 
5101     long nr_hilb = HilbertBasis.nr_of_rows();
5102     // if the cone is not pointed, we have to check it on the quotion
5103     Matrix<Integer> gens_quot;
5104     Matrix<Integer> hilb_quot;
5105     if (!pointed) {
5106         gens_quot = BasisChangePointed.to_sublattice(InputGenerators);
5107         hilb_quot = BasisChangePointed.to_sublattice(HilbertBasis);
5108     }
5109     Matrix<Integer>& gens = pointed ? InputGenerators : gens_quot;
5110     Matrix<Integer>& hilb = pointed ? HilbertBasis : hilb_quot;
5111     integrally_closed = true;
5112 
5113     set<vector<Integer> > gens_set;
5114     gens_set.insert(gens.get_elements().begin(),gens.get_elements().end());
5115     integrally_closed=true;
5116     for (long h = 0; h < nr_hilb; ++h) {
5117         if(gens_set.find(hilb[h])==gens_set.end()){
5118             integrally_closed = false;
5119             if(ToCompute.test(ConeProperty::WitnessNotIntegrallyClosed)){
5120                 WitnessNotIntegrallyClosed = HilbertBasis[h];
5121                 setComputed(ConeProperty::WitnessNotIntegrallyClosed);
5122             }
5123             break;
5124 
5125         }
5126     }
5127     setComputed(ConeProperty::IsIntegrallyClosed);
5128 }
5129 
5130 //---------------------------------------------------------------------------
5131 
5132 template <typename Integer>
set_original_monoid_generators(const Matrix<Integer> & Input)5133 void Cone<Integer>::set_original_monoid_generators(const Matrix<Integer>& Input) {
5134 
5135     InputGenerators = Input;
5136     if(using_renf<Integer>())
5137         return;
5138 
5139     if (!isComputed(ConeProperty::OriginalMonoidGenerators)) {
5140         setComputed(ConeProperty::OriginalMonoidGenerators);
5141     }
5142     // Generators = Input;
5143     // setComputed(ConeProperty::Generators);
5144     Matrix<Integer> M = BasisChange.to_sublattice(Input);
5145     internal_index = M.full_rank_index();
5146     setComputed(ConeProperty::InternalIndex);
5147 }
5148 
5149 //---------------------------------------------------------------------------
5150 
5151 template <typename Integer>
set_extreme_rays(const vector<bool> & ext)5152 void Cone<Integer>::set_extreme_rays(const vector<bool>& ext) {
5153 
5154     assert(ext.size() == Generators.nr_of_rows());
5155     ExtremeRaysIndicator = ext;
5156 
5157     if(isComputed(ConeProperty::ExtremeRays))
5158         return;
5159 
5160     ExtremeRays = Generators.submatrix(ext);  // extreme rays of the homogenized cone
5161     vector<bool> choice = ext;
5162     if (inhomogeneous) {
5163         // separate extreme rays to rays of the level 0 cone
5164         // and the verticies of the polyhedron, which are in level >=1
5165         size_t nr_gen = Generators.nr_of_rows();
5166         vector<bool> VOP(nr_gen);
5167         for (size_t i = 0; i < nr_gen; i++) {
5168             if (ext[i] && v_scalar_product(Generators[i], Dehomogenization) != 0) {
5169                 VOP[i] = true;
5170                 choice[i] = false;
5171             }
5172         }
5173         VerticesOfPolyhedron = Generators.submatrix(VOP);
5174         if (using_renf<Integer>())
5175             VerticesOfPolyhedron.standardize_rows(Norm);
5176         VerticesOfPolyhedron.sort_by_weights(WeightsGrad, GradAbs);
5177         setComputed(ConeProperty::VerticesOfPolyhedron);
5178     }
5179     ExtremeRaysRecCone = Generators.submatrix(choice);
5180 
5181     if (inhomogeneous && !isComputed(ConeProperty::AffineDim) && isComputed(ConeProperty::MaximalSubspace)) {
5182         size_t level0_dim = ExtremeRaysRecCone.max_rank_submatrix_lex().size();
5183         recession_rank = level0_dim + BasisMaxSubspace.nr_of_rows();
5184         setComputed(ConeProperty::RecessionRank);
5185         if (get_rank_internal() == recession_rank) {
5186             affine_dim = -1;
5187         }
5188         else {
5189             affine_dim = get_rank_internal() - 1;
5190         }
5191         setComputed(ConeProperty::AffineDim);
5192     }
5193     if (isComputed(ConeProperty::ModuleGeneratorsOverOriginalMonoid)) {
5194         Matrix<Integer> ExteEmbedded = BasisChangePointed.to_sublattice(ExtremeRaysRecCone);  // done to extract gcd
5195         for (size_t i = 0; i < ExteEmbedded.nr_of_rows(); ++i)  // not always done for original monoid generators
5196             v_make_prime(ExteEmbedded[i]);                      // Moreover, several generators can give the same xtreme ray
5197         ExteEmbedded.remove_duplicate_and_zero_rows();
5198         ExtremeRaysRecCone = BasisChangePointed.from_sublattice(ExteEmbedded);
5199     }
5200 
5201     if (using_renf<Integer>()) {
5202         ExtremeRays.standardize_rows(Norm);
5203         ExtremeRaysRecCone.standardize_rows(Norm);
5204     }
5205     ExtremeRays.sort_by_weights(WeightsGrad, GradAbs);
5206     ExtremeRaysRecCone.sort_by_weights(WeightsGrad, GradAbs);
5207     setComputed(ConeProperty::ExtremeRays);
5208     addition_generators_allowed = true;
5209 }
5210 
5211 //---------------------------------------------------------------------------
5212 
5213 template <typename Integer>
compute_vertices_float(ConeProperties & ToCompute)5214 void Cone<Integer>::compute_vertices_float(ConeProperties& ToCompute) {
5215     if (!ToCompute.test(ConeProperty::VerticesFloat) || isComputed(ConeProperty::VerticesFloat))
5216         return;
5217     if (!isComputed(ConeProperty::ExtremeRays))
5218         throw NotComputableException("VerticesFloat not computable without extreme rays");
5219     if (inhomogeneous && !isComputed(ConeProperty::VerticesOfPolyhedron))
5220         throw NotComputableException("VerticesFloat not computable in the inhomogeneous case without vertices");
5221     if (!inhomogeneous && !isComputed(ConeProperty::Grading))
5222         throw NotComputableException("VerticesFloat not computable in the homogeneous case without a grading");
5223     if (inhomogeneous)
5224         convert(VerticesFloat, VerticesOfPolyhedron);
5225     else
5226         convert(VerticesFloat, ExtremeRays);
5227     vector<nmz_float> norm;
5228     if (inhomogeneous)
5229         convert(norm, Dehomogenization);
5230     else {
5231         convert(norm, Grading);
5232         nmz_float GD = 1.0 / convertTo<double>(GradingDenom);
5233         v_scalar_multiplication(norm, GD);
5234     }
5235     VerticesFloat.standardize_rows(norm);
5236     setComputed(ConeProperty::VerticesFloat);
5237 }
5238 
5239 //---------------------------------------------------------------------------
5240 
5241 template <typename Integer>
compute_extreme_rays_float(ConeProperties & ToCompute)5242 void Cone<Integer>::compute_extreme_rays_float(ConeProperties& ToCompute) {
5243     if (!ToCompute.test(ConeProperty::ExtremeRaysFloat) || isComputed(ConeProperty::ExtremeRaysFloat))
5244         return;
5245     if (!isComputed(ConeProperty::ExtremeRays))
5246         throw NotComputableException("ExtremeRaysFloat not computable without extreme rays");
5247     if (inhomogeneous)
5248         convert(ExtremeRaysFloat, ExtremeRaysRecCone);
5249     else
5250         convert(ExtremeRaysFloat, ExtremeRays);
5251     vector<nmz_float> norm;
5252     if (!inhomogeneous){
5253             if(isComputed(ConeProperty::Grading)){
5254             convert(norm, Grading);
5255             nmz_float GD = 1.0 / convertTo<double>(GradingDenom);
5256             v_scalar_multiplication(norm, GD);
5257         }
5258     }
5259     ExtremeRaysFloat.standardize_rows(norm);
5260     setComputed(ConeProperty::ExtremeRaysFloat);
5261 }
5262 
5263 //---------------------------------------------------------------------------
5264 
5265 template <typename Integer>
compute_supp_hyps_float(ConeProperties & ToCompute)5266 void Cone<Integer>::compute_supp_hyps_float(ConeProperties& ToCompute) {
5267     if (!ToCompute.test(ConeProperty::SuppHypsFloat) || isComputed(ConeProperty::SuppHypsFloat))
5268         return;
5269     if (!isComputed(ConeProperty::SupportHyperplanes))
5270         throw NotComputableException("SuppHypsFloat not computable without support hyperplanes");
5271 
5272     convert(SuppHypsFloat, SupportHyperplanes);
5273     SuppHypsFloat.standardize_rows();
5274     setComputed(ConeProperty::SuppHypsFloat);
5275 }
5276 
5277 //---------------------------------------------------------------------------
5278 
5279 template <typename Integer>
complete_sublattice_comp(ConeProperties & ToCompute)5280 void Cone<Integer>::complete_sublattice_comp(ConeProperties& ToCompute) {
5281     if (!isComputed(ConeProperty::Sublattice))
5282         return;
5283     setComputed(ConeProperty::Rank);
5284     if (ToCompute.test(ConeProperty::Equations)) {
5285         BasisChange.getEquationsMatrix();  // just to force computation, ditto below
5286         setComputed(ConeProperty::Equations);
5287     }
5288     if (ToCompute.test(ConeProperty::Congruences) || ToCompute.test(ConeProperty::ExternalIndex)) {
5289         BasisChange.getCongruencesMatrix();
5290         BasisChange.getExternalIndex();
5291         setComputed(ConeProperty::Congruences);
5292         setComputed(ConeProperty::ExternalIndex);
5293     }
5294 }
5295 
5296 template <typename Integer>
complete_HilbertSeries_comp(ConeProperties & ToCompute)5297 void Cone<Integer>::complete_HilbertSeries_comp(ConeProperties& ToCompute) {
5298     if (!isComputed(ConeProperty::HilbertSeries) && !isComputed(ConeProperty::EhrhartSeries))
5299         return;
5300     if (ToCompute.test(ConeProperty::HilbertQuasiPolynomial) || ToCompute.test(ConeProperty::EhrhartQuasiPolynomial))
5301         HSeries.computeHilbertQuasiPolynomial();
5302     if (HSeries.isHilbertQuasiPolynomialComputed()) {
5303         setComputed(ConeProperty::HilbertQuasiPolynomial);
5304         setComputed(ConeProperty::EhrhartQuasiPolynomial);
5305     }
5306 
5307     if (!inhomogeneous && !isComputed(ConeProperty::NumberLatticePoints) && ExcludedFaces.nr_of_rows() == 0) {
5308         // note: ConeProperty::ExcludedFaces not necessarily set TODO
5309         long save_expansion_degree = HSeries.get_expansion_degree();
5310         HSeries.set_expansion_degree(1);
5311         vector<mpz_class> expansion = HSeries.getExpansion();
5312         HSeries.set_expansion_degree(save_expansion_degree);
5313         long long nlp = 0;
5314         if (expansion.size() > 1) {
5315             nlp = convertToLongLong(expansion[1]);
5316         }
5317         number_lattice_points = nlp;
5318         setComputed(ConeProperty::NumberLatticePoints);
5319     }
5320 
5321     // we want to be able to convert HS ohr EhrS to hsop denom if
5322     // they have been computed without
5323 
5324     if (! (ToCompute.test(ConeProperty::HSOP) && !isComputed(ConeProperty::HSOP) &&
5325           (isComputed(ConeProperty::HilbertSeries) || isComputed(ConeProperty::EhrhartSeries))))  // everything done already
5326         return;
5327 
5328     compute(ConeProperty::ExtremeRays);
5329     if (inhomogeneous && !isComputed(ConeProperty::EhrhartSeries) && ExtremeRaysRecCone.nr_of_rows() == 0)
5330         return;  // in this case the Hilbert series is a polynomial and the Ehrhart series is not available
5331 
5332     Matrix<Integer> FC_gens;
5333     FC_gens = BasisChangePointed.to_sublattice(ExtremeRays);
5334     /* if(inhomogeneous){
5335         FC_gens.append(BasisChangePointed.to_sublattice(VerticesOfPolyhedron));
5336     }*/
5337     Full_Cone<Integer> FC(FC_gens);
5338 
5339     FC.inhomogeneous = inhomogeneous && !isComputed(ConeProperty::EhrhartSeries);
5340 
5341     FC.Support_Hyperplanes = BasisChangePointed.to_sublattice_dual(SupportHyperplanes);
5342     FC.dualize_cone();  // minimizes support hyperplanes
5343 
5344     if (!inhomogeneous || !isComputed(ConeProperty::EhrhartSeries)) {
5345         if (ToCompute.test(ConeProperty::NoGradingDenom))
5346             BasisChangePointed.convert_to_sublattice_dual_no_div(FC.Grading, Grading);
5347         else
5348             BasisChangePointed.convert_to_sublattice_dual(FC.Grading, Grading);
5349         FC.is_Computed.set(ConeProperty::Grading);
5350     }
5351     else {
5352         FC.Grading = BasisChangePointed.to_sublattice_dual_no_div(Dehomogenization);
5353     }
5354     if (FC.inhomogeneous)
5355         FC.Truncation = BasisChangePointed.to_sublattice_dual_no_div(Dehomogenization);
5356     FC.Extreme_Rays_Ind = vector<bool>(FC_gens.nr_of_rows(), true);
5357     FC.is_Computed.set(ConeProperty::ExtremeRays);
5358 
5359     FC.compute_hsop();
5360 
5361     if (isComputed(ConeProperty::EhrhartSeries)) {
5362         EhrSeries.setHSOPDenom(FC.Hilbert_Series.getHSOPDenom());
5363         EhrSeries.compute_hsop_num();
5364     }
5365     else {  // we have a proper Hilbert series which is not a polynomial
5366         if (isComputed(ConeProperty::HilbertSeries)) {
5367             HSeries.setHSOPDenom(FC.Hilbert_Series.getHSOPDenom());
5368             HSeries.compute_hsop_num();
5369         }
5370     }
5371     setComputed(ConeProperty::HSOP);
5372 }
5373 
5374 //---------------------------------------------------------------------------
5375 
5376 template <typename Integer>
setNumericalParams(const map<NumParam::Param,long> & num_params)5377 void Cone<Integer>::setNumericalParams(const map<NumParam::Param, long>& num_params) {
5378     auto np = num_params.find(NumParam::expansion_degree);
5379     if (np != num_params.end())
5380         setExpansionDegree(np->second);
5381     np = num_params.find(NumParam::nr_coeff_quasipol);
5382     if (np != num_params.end())
5383         setNrCoeffQuasiPol(np->second);
5384     np = num_params.find(NumParam::face_codim_bound);
5385     if (np != num_params.end())
5386         setFaceCodimBound(np->second);
5387     np = num_params.find(NumParam::autom_codim_bound_vectors);
5388     if (np != num_params.end())
5389         setAutomCodimBoundVectors(np->second);
5390     np = num_params.find(NumParam::decimal_digits);
5391     if (np != num_params.end())
5392         setDecimalDigits(np->second);
5393     np = num_params.find(NumParam::block_size_hollow_tri);
5394     if (np != num_params.end())
5395         setBlocksizeHollowTri(np->second);
5396 }
5397 
5398 template <typename Integer>
setPolynomial(string poly)5399 void Cone<Integer>::setPolynomial(string poly) {
5400     IntData = IntegrationData(poly);
5401     is_Computed.reset(ConeProperty::WeightedEhrhartSeries);
5402     is_Computed.reset(ConeProperty::WeightedEhrhartQuasiPolynomial);
5403     is_Computed.reset(ConeProperty::Integral);
5404     is_Computed.reset(ConeProperty::EuclideanIntegral);
5405     is_Computed.reset(ConeProperty::VirtualMultiplicity);
5406 }
5407 
5408 template <typename Integer>
setNrCoeffQuasiPol(long nr_coeff)5409 void Cone<Integer>::setNrCoeffQuasiPol(long nr_coeff) {
5410     HSeries.resetHilbertQuasiPolynomial();
5411     IntData.set_nr_coeff_quasipol(nr_coeff);
5412     is_Computed.reset(ConeProperty::WeightedEhrhartQuasiPolynomial);
5413     IntData.resetHilbertQuasiPolynomial();
5414     HSeries.set_nr_coeff_quasipol(nr_coeff);
5415     is_Computed.reset(ConeProperty::HilbertQuasiPolynomial);
5416 }
5417 
5418 template <typename Integer>
setExpansionDegree(long degree)5419 void Cone<Integer>::setExpansionDegree(long degree) {
5420     IntData.set_expansion_degree(degree);
5421     HSeries.set_expansion_degree(degree);
5422     EhrSeries.set_expansion_degree(degree);
5423 }
5424 
5425 template <typename Integer>
setFaceCodimBound(long bound)5426 void Cone<Integer>::setFaceCodimBound(long bound) {
5427     face_codim_bound = bound;
5428     is_Computed.reset(ConeProperty::FaceLattice);
5429     is_Computed.reset(ConeProperty::FVector);
5430     is_Computed.reset(ConeProperty::DualFaceLattice);
5431     is_Computed.reset(ConeProperty::DualFVector);
5432     FaceLat.clear();
5433     DualFaceLat.clear();
5434     dual_f_vector.clear();
5435     f_vector.clear();
5436 }
5437 
5438 template <typename Integer>
setAutomCodimBoundMult(long bound)5439 void Cone<Integer>::setAutomCodimBoundMult(long bound) {
5440     autom_codim_mult = bound;
5441 }
5442 
5443 template <typename Integer>
setAutomCodimBoundVectors(long bound)5444 void Cone<Integer>::setAutomCodimBoundVectors(long bound) {
5445     autom_codim_vectors = bound;
5446 }
5447 
5448 template <typename Integer>
setDecimalDigits(long digits)5449 void Cone<Integer>::setDecimalDigits(long digits) {
5450     decimal_digits = digits;
5451 }
5452 
5453 template <typename Integer>
setBlocksizeHollowTri(long block_size)5454 void Cone<Integer>::setBlocksizeHollowTri(long block_size) {
5455     block_size_hollow_tri = block_size;
5456 }
5457 
5458 template <typename Integer>
setProjectName(const string & my_project)5459 void Cone<Integer>::setProjectName(const string& my_project) {
5460     project_name = my_project;
5461 }
5462 
5463 template <typename Integer>
getProjectName() const5464 string Cone<Integer>::getProjectName() const {
5465     return project_name;
5466 }
5467 
5468 //---------------------------------------------------------------------------
5469 template <typename Integer>
try_symmetrization(ConeProperties & ToCompute)5470 void Cone<Integer>::try_symmetrization(ConeProperties& ToCompute) {
5471     if (dim <= 1 || using_renf<Integer>())
5472         return;
5473 
5474     if (ToCompute.test(ConeProperty::NoSymmetrization) || ToCompute.test(ConeProperty::Descent))
5475         return;
5476 
5477     if (!(ToCompute.test(ConeProperty::Symmetrize) || ToCompute.test(ConeProperty::HilbertSeries) ||
5478           ToCompute.test(ConeProperty::Multiplicity)))
5479         return;
5480 
5481     if (inhomogeneous || nr_latt_gen > 0 || nr_cone_gen > 0 || lattice_ideal_input || Grading.size() < dim) {
5482         if (ToCompute.test(ConeProperty::Symmetrize))
5483             throw BadInputException("Symmetrization not possible with the given input");
5484         else
5485             return;
5486     }
5487 
5488 #ifndef NMZ_COCOA
5489     if (ToCompute.test(ConeProperty::Symmetrize)) {
5490         throw BadInputException("Symmetrization not possible without CoCoALib");
5491     }
5492     else
5493         return;
5494 #endif
5495 
5496     Matrix<Integer> AllConst = ExcludedFaces;
5497     size_t nr_excl = AllConst.nr_of_rows();
5498     AllConst.append(Equations);
5499     size_t nr_equ = AllConst.nr_of_rows() - nr_excl;
5500     vector<bool> unit_vector(dim, false);
5501     for (size_t i = 0; i < Inequalities.nr_of_rows(); ++i) {
5502         size_t nr_nonzero = 0;
5503         size_t nonzero_coord;
5504         bool is_unit_vector = true;
5505         bool is_zero = true;
5506         for (size_t j = 0; j < dim; ++j) {
5507             if (Inequalities[i][j] == 0)
5508                 continue;
5509             is_zero = false;
5510             if (nr_nonzero > 0 || Inequalities[i][j] != 1) {  // not a sign inequality
5511                 is_unit_vector = false;
5512                 break;
5513             }
5514             nr_nonzero++;
5515             nonzero_coord = j;
5516         }
5517         if (is_zero)  // tatological inequality superfluous
5518             continue;
5519         if (!is_unit_vector)
5520             AllConst.append(Inequalities[i]);
5521         else
5522             unit_vector[nonzero_coord] = true;
5523     }
5524 
5525     size_t nr_inequ = AllConst.nr_of_rows() - nr_equ - nr_excl;
5526 
5527     for (size_t i = 0; i < dim; ++i)
5528         if (!unit_vector[i]) {
5529             if (ToCompute.test(ConeProperty::Symmetrize))
5530                 throw BadInputException("Symmetrization not possible: Not all sign inequalities in input");
5531             else
5532                 return;
5533         }
5534 
5535     for (size_t i = 0; i < Congruences.nr_of_rows(); ++i) {
5536         vector<Integer> help = Congruences[i];
5537         help.resize(dim);
5538         AllConst.append(help);
5539     }
5540     // now we have collected all constraints and checked the existence of the sign inequalities
5541 
5542     AllConst.append(Grading);
5543 
5544     /* AllConst.pretty_print(cout);
5545     cout << "----------------------" << endl;
5546     cout << nr_excl << " " << nr_equ << " " << nr_inequ << endl; */
5547 
5548     AllConst = AllConst.transpose();
5549 
5550     map<vector<Integer>, size_t> classes;
5551 
5552     for (size_t j = 0; j < AllConst.nr_of_rows(); ++j) {
5553         auto C = classes.find(AllConst[j]);
5554         if (C != classes.end())
5555             C->second++;
5556         else
5557             classes.insert(pair<vector<Integer>, size_t>(AllConst[j], 1));
5558     }
5559 
5560     vector<size_t> multiplicities;
5561     Matrix<Integer> SymmConst(0, AllConst.nr_of_columns());
5562 
5563     for (const auto& C : classes) {
5564         multiplicities.push_back(C.second);
5565         SymmConst.append(C.first);
5566     }
5567     SymmConst = SymmConst.transpose();
5568 
5569     vector<Integer> SymmGrad = SymmConst[SymmConst.nr_of_rows() - 1];
5570 
5571     if (verbose) {
5572         verboseOutput() << "Embedding dimension of symmetrized cone = " << SymmGrad.size() << endl;
5573     }
5574 
5575     if (SymmGrad.size() > 2 * dim / 3) {
5576         if (!ToCompute.test(ConeProperty::Symmetrize)) {
5577             return;
5578         }
5579     }
5580 
5581     /* compute_generators(); // we must protect against the zero cone
5582     if(get_rank_internal()==0)
5583         return; */
5584 
5585     Matrix<Integer> SymmInequ(0, SymmConst.nr_of_columns());
5586     Matrix<Integer> SymmEqu(0, SymmConst.nr_of_columns());
5587     Matrix<Integer> SymmCong(0, SymmConst.nr_of_columns());
5588     Matrix<Integer> SymmExcl(0, SymmConst.nr_of_columns());
5589 
5590     for (size_t i = 0; i < nr_excl; ++i)
5591         SymmExcl.append(SymmConst[i]);
5592     for (size_t i = nr_excl; i < nr_excl + nr_equ; ++i)
5593         SymmEqu.append(SymmConst[i]);
5594     for (size_t i = nr_excl + nr_equ; i < nr_excl + nr_equ + nr_inequ; ++i)
5595         SymmInequ.append(SymmConst[i]);
5596     for (size_t i = nr_excl + nr_equ + nr_inequ; i < SymmConst.nr_of_rows() - 1; ++i) {
5597         SymmCong.append(SymmConst[i]);
5598         SymmCong[SymmCong.nr_of_rows() - 1].push_back(Congruences[i - (nr_inequ + nr_equ)][dim]);  // restore modulus
5599     }
5600 
5601     string polynomial;
5602 
5603     for (size_t i = 0; i < multiplicities.size(); ++i) {
5604         for (size_t j = 1; j < multiplicities[i]; ++j)
5605             polynomial += "(x[" + to_string((unsigned long long)i + 1) + "]+" + to_string((unsigned long long)j) + ")|";
5606     }
5607     polynomial += "1";
5608     mpz_class fact = 1;
5609     for (unsigned long multiplicitie : multiplicities) {
5610         for (size_t j = 1; j < multiplicitie; ++j)
5611             fact *= static_cast<unsigned long>(j);
5612     }
5613     polynomial += "/" + fact.get_str() + ";";
5614 
5615 #ifdef NMZ_COCOA
5616 
5617     map<InputType, Matrix<Integer> > SymmInput;
5618     SymmInput[InputType::inequalities] = SymmInequ;
5619     SymmInput[InputType::equations] = SymmEqu;
5620     SymmInput[InputType::congruences] = SymmCong;
5621     SymmInput[InputType::excluded_faces] = SymmExcl;
5622     SymmInput[InputType::grading] = SymmGrad;
5623     vector<Integer> NonNeg(SymmGrad.size(), 1);
5624     SymmInput[InputType::signs] = NonNeg;
5625 
5626     if (SymmCone != NULL)
5627         delete SymmCone;
5628 
5629     SymmCone = new Cone<Integer>(SymmInput);
5630     SymmCone->setPolynomial(polynomial);
5631     SymmCone->setDecimalDigits(decimal_digits);
5632     SymmCone->setNrCoeffQuasiPol(HSeries.get_nr_coeff_quasipol());
5633     SymmCone->HSeries.set_period_bounded(HSeries.get_period_bounded());
5634     SymmCone->setVerbose(verbose);
5635     ConeProperties SymmToCompute;
5636     SymmToCompute.set(ConeProperty::SupportHyperplanes);
5637     SymmToCompute.set(ConeProperty::WeightedEhrhartSeries, ToCompute.test(ConeProperty::HilbertSeries));
5638     SymmToCompute.set(ConeProperty::VirtualMultiplicity, ToCompute.test(ConeProperty::Multiplicity));
5639     SymmToCompute.set(ConeProperty::BottomDecomposition, ToCompute.test(ConeProperty::BottomDecomposition));
5640     SymmToCompute.set(ConeProperty::NoGradingDenom, ToCompute.test(ConeProperty::NoGradingDenom));
5641     SymmToCompute.set(ConeProperty::SignedDec, ToCompute.test(ConeProperty::SignedDec));
5642     SymmToCompute.set(ConeProperty::NoSignedDec, ToCompute.test(ConeProperty::NoSignedDec));
5643     SymmToCompute.set(ConeProperty::GradingIsPositive, ToCompute.test(ConeProperty::GradingIsPositive));
5644     SymmToCompute.set(ConeProperty::FixedPrecision, ToCompute.test(ConeProperty::FixedPrecision));
5645     SymmCone->compute(SymmToCompute);
5646     if (SymmCone->isComputed(ConeProperty::WeightedEhrhartSeries)) {
5647         long save_expansion_degree = HSeries.get_expansion_degree();  // not given to the symmetrization
5648         HSeries = SymmCone->getWeightedEhrhartSeries().first;
5649         HSeries.set_expansion_degree(save_expansion_degree);
5650         setComputed(ConeProperty::HilbertSeries);
5651         // setComputed(ConeProperty::ExplicitHilbertSeries);
5652     }
5653     if (SymmCone->isComputed(ConeProperty::VirtualMultiplicity)) {
5654         multiplicity = SymmCone->getVirtualMultiplicity();
5655         setComputed(ConeProperty::Multiplicity);
5656     }
5657     if (SymmCone->isComputed(ConeProperty::FixedPrecision)) {
5658         setComputed(ConeProperty::FixedPrecision);
5659     }
5660     setComputed(ConeProperty::Symmetrize);
5661     ToCompute.set(ConeProperty::NoGradingDenom);
5662     return;
5663 
5664 #endif
5665 }
5666 
5667 template <typename Integer>
5668 void integrate(Cone<Integer>& C, const bool do_virt_mult);
5669 
5670 template <typename Integer>
5671 void generalizedEhrhartSeries(Cone<Integer>& C);
5672 
5673 template <typename Integer>
compute_integral(ConeProperties & ToCompute)5674 void Cone<Integer>::compute_integral(ConeProperties& ToCompute) {
5675     if (isComputed(ConeProperty::Integral) || !ToCompute.test(ConeProperty::Integral))
5676         return;
5677     if (BasisMaxSubspace.nr_of_rows() > 0)
5678         throw NotComputableException("Integral not computable for polyhedra containing an affine space of dim > 0");
5679     if (IntData.getPolynomial() == "")
5680         throw BadInputException("Polynomial weight missing");
5681 #ifdef NMZ_COCOA
5682     if (get_rank_internal() == 0) {
5683         getIntData().setIntegral(0);
5684         getIntData().setEuclideanIntegral(0);
5685     }
5686     else {
5687         integrate<Integer>(*this, false);
5688     }
5689     setComputed(ConeProperty::Integral);
5690     setComputed(ConeProperty::EuclideanIntegral);
5691 #endif
5692 }
5693 
5694 template <typename Integer>
compute_virt_mult(ConeProperties & ToCompute)5695 void Cone<Integer>::compute_virt_mult(ConeProperties& ToCompute) {
5696     if (isComputed(ConeProperty::VirtualMultiplicity) || !ToCompute.test(ConeProperty::VirtualMultiplicity))
5697         return;
5698     if (BasisMaxSubspace.nr_of_rows() > 0)
5699         throw NotComputableException("Virtual multiplicity not computable for polyhedra containing an affine space of dim > 0");
5700     if (IntData.getPolynomial() == "")
5701         throw BadInputException("Polynomial weight missing");
5702 #ifdef NMZ_COCOA
5703     if (get_rank_internal() == 0)
5704         getIntData().setVirtualMultiplicity(0);
5705     else
5706         integrate<Integer>(*this, true);
5707     setComputed(ConeProperty::VirtualMultiplicity);
5708 #endif
5709 }
5710 
5711 template <typename Integer>
compute_weighted_Ehrhart(ConeProperties & ToCompute)5712 void Cone<Integer>::compute_weighted_Ehrhart(ConeProperties& ToCompute) {
5713     if (isComputed(ConeProperty::WeightedEhrhartSeries) || !ToCompute.test(ConeProperty::WeightedEhrhartSeries))
5714         return;
5715     if (BasisMaxSubspace.nr_of_rows() > 0)
5716         throw NotComputableException("Weighted Ehrhart series not computable for polyhedra containing an affine space of dim > 0");
5717     if (IntData.getPolynomial() == "")
5718         throw BadInputException("Polynomial weight missing");
5719         /* if(get_rank_internal()==0)
5720             throw NotComputableException("WeightedEhrhartSeries not computed in dimenison 0");*/
5721 #ifdef NMZ_COCOA
5722     generalizedEhrhartSeries(*this);
5723     setComputed(ConeProperty::WeightedEhrhartSeries);
5724     if (getIntData().isWeightedEhrhartQuasiPolynomialComputed()) {
5725         setComputed(ConeProperty::WeightedEhrhartQuasiPolynomial);
5726         setComputed(ConeProperty::VirtualMultiplicity);
5727     }
5728 #endif
5729 }
5730 
5731 #ifdef ENFNORMALIZ
5732 template <>
compute_weighted_Ehrhart(ConeProperties & ToCompute)5733 void Cone<renf_elem_class>::compute_weighted_Ehrhart(ConeProperties& ToCompute) {
5734     assert(false);
5735 }
5736 
5737 template <>
compute_virt_mult(ConeProperties & ToCompute)5738 void Cone<renf_elem_class>::compute_virt_mult(ConeProperties& ToCompute) {
5739     assert(false);
5740 }
5741 
5742 template <>
compute_integral(ConeProperties & ToCompute)5743 void Cone<renf_elem_class>::compute_integral(ConeProperties& ToCompute) {
5744     assert(false);
5745 }
5746 #endif
5747 //---------------------------------------------------------------------------
5748 template <typename Integer>
get_verbose()5749 bool Cone<Integer>::get_verbose() {
5750     return verbose;
5751 }
5752 
5753 //---------------------------------------------------------------------------
5754 template <typename Integer>
check_Gorenstein(ConeProperties & ToCompute)5755 void Cone<Integer>::check_Gorenstein(ConeProperties& ToCompute) {
5756     if (!ToCompute.test(ConeProperty::IsGorenstein) || isComputed(ConeProperty::IsGorenstein))
5757         return;
5758     if (!isComputed(ConeProperty::SupportHyperplanes))
5759         compute(ConeProperty::SupportHyperplanes);
5760     if (!isComputed(ConeProperty::MaximalSubspace))
5761         compute(ConeProperty::MaximalSubspace);
5762 
5763     if (dim == 0) {
5764         Gorenstein = true;
5765         setComputed(ConeProperty::IsGorenstein);
5766         GeneratorOfInterior = vector<Integer>(dim, 0);
5767         setComputed(ConeProperty::GeneratorOfInterior);
5768         return;
5769     }
5770     Matrix<Integer> TransfSupps = BasisChangePointed.to_sublattice_dual(SupportHyperplanes);
5771     assert(TransfSupps.nr_of_rows() > 0);
5772     Gorenstein = false;
5773     vector<Integer> TransfIntGen = TransfSupps.find_linear_form();
5774     if (TransfIntGen.size() != 0 && v_scalar_product(TransfIntGen, TransfSupps[0]) == 1) {
5775         Gorenstein = true;
5776         GeneratorOfInterior = BasisChangePointed.from_sublattice(TransfIntGen);
5777         setComputed(ConeProperty::GeneratorOfInterior);
5778     }
5779     setComputed(ConeProperty::IsGorenstein);
5780 }
5781 
5782 //---------------------------------------------------------------------------
5783 template <typename Integer>
5784 template <typename IntegerFC>
give_data_of_approximated_cone_to(Full_Cone<IntegerFC> & FC)5785 void Cone<Integer>::give_data_of_approximated_cone_to(Full_Cone<IntegerFC>& FC) {
5786     // *this is the approximatING cone. The support hyperplanes and equations of the approximatED
5787     // cone are given to the Full_Cone produced from *this so that the superfluous points can
5788     // bre sorted out as early as possible.
5789 
5790     assert(is_approximation);
5791     assert(ApproximatedCone->inhomogeneous || ApproximatedCone->getGradingDenom() == 1);  // in case we generalize later
5792 
5793     FC.is_global_approximation = true;
5794     // FC.is_approximation=true; At present not allowed. Only used for approximation within Full_Cone
5795 
5796     // We must distinguish zwo cases: Approximated->Grading_Is_Coordinate or it is not
5797 
5798     // If it is not:
5799     // The first coordinate in *this is the degree given by the grading
5800     // in ApproximatedCone. We disregard it by setting the first coordinate
5801     // of the grading, inequalities and equations to 0, and then have 0 followed
5802     // by the grading, equations and inequalities resp. of ApproximatedCone.
5803 
5804     vector<Integer> help_g;
5805     if (ApproximatedCone->inhomogeneous)
5806         help_g = ApproximatedCone->Dehomogenization;
5807     else
5808         help_g = ApproximatedCone->Grading;
5809 
5810     if (ApproximatedCone->Grading_Is_Coordinate) {
5811         swap(help_g[0], help_g[ApproximatedCone->GradingCoordinate]);
5812         BasisChangePointed.convert_to_sublattice_dual_no_div(FC.Subcone_Grading, help_g);
5813     }
5814     else {
5815         vector<Integer> help(help_g.size() + 1);
5816         help[0] = 0;
5817         for (size_t j = 0; j < help_g.size(); ++j)
5818             help[j + 1] = help_g[j];
5819         BasisChangePointed.convert_to_sublattice_dual_no_div(FC.Subcone_Grading, help);
5820     }
5821 
5822     Matrix<Integer> Eq = ApproximatedCone->BasisChangePointed.getEquationsMatrix();
5823     FC.Subcone_Equations = Matrix<IntegerFC>(Eq.nr_of_rows(), BasisChangePointed.getRank());
5824     if (ApproximatedCone->Grading_Is_Coordinate) {
5825         Eq.exchange_columns(0, ApproximatedCone->GradingCoordinate);
5826         BasisChangePointed.convert_to_sublattice_dual(FC.Subcone_Equations, Eq);
5827     }
5828     else {
5829         for (size_t i = 0; i < Eq.nr_of_rows(); ++i) {
5830             vector<Integer> help(Eq.nr_of_columns() + 1, 0);
5831             for (size_t j = 0; j < Eq.nr_of_columns(); ++j)
5832                 help[j + 1] = Eq[i][j];
5833             BasisChangePointed.convert_to_sublattice_dual(FC.Subcone_Equations[i], help);
5834         }
5835     }
5836 
5837     Matrix<Integer> Supp = ApproximatedCone->SupportHyperplanes;
5838     FC.Subcone_Support_Hyperplanes = Matrix<IntegerFC>(Supp.nr_of_rows(), BasisChangePointed.getRank());
5839 
5840     if (ApproximatedCone->Grading_Is_Coordinate) {
5841         Supp.exchange_columns(0, ApproximatedCone->GradingCoordinate);
5842         BasisChangePointed.convert_to_sublattice_dual(FC.Subcone_Support_Hyperplanes, Supp);
5843     }
5844     else {
5845         for (size_t i = 0; i < Supp.nr_of_rows(); ++i) {
5846             vector<Integer> help(Supp.nr_of_columns() + 1, 0);
5847             for (size_t j = 0; j < Supp.nr_of_columns(); ++j)
5848                 help[j + 1] = Supp[i][j];
5849             BasisChangePointed.convert_to_sublattice_dual(FC.Subcone_Support_Hyperplanes[i], help);
5850         }
5851     }
5852 }
5853 
5854 //---------------------------------------------------------------------------
5855 template <typename Integer>
try_approximation_or_projection(ConeProperties & ToCompute)5856 void Cone<Integer>::try_approximation_or_projection(ConeProperties& ToCompute) {
5857     if ((ToCompute.test(ConeProperty::NoProjection) && !ToCompute.test(ConeProperty::Approximate)) ||
5858         ToCompute.test(ConeProperty::DualMode) || ToCompute.test(ConeProperty::PrimalMode) ||
5859         ToCompute.test(ConeProperty::ExploitAutomsVectors))
5860         return;
5861 
5862     if (ToCompute.test(ConeProperty::ModuleGeneratorsOverOriginalMonoid))
5863         return;
5864 
5865     if (!inhomogeneous && (!(ToCompute.test(ConeProperty::Deg1Elements) || ToCompute.test(ConeProperty::NumberLatticePoints)) ||
5866                            ToCompute.test(ConeProperty::HilbertBasis) || ToCompute.test(ConeProperty::HilbertSeries)))
5867         return;
5868 
5869     if (inhomogeneous && (!ToCompute.test(ConeProperty::HilbertBasis) && !ToCompute.test(ConeProperty::NumberLatticePoints)))
5870         return;
5871 
5872     bool polytope_check_done = false;
5873     if (inhomogeneous && isComputed(ConeProperty::Generators)) {  // try to catch unbounded polyhedra as early as possible
5874         polytope_check_done = true;
5875         for (size_t i = 0; i < Generators.nr_of_rows(); ++i) {
5876             if (v_scalar_product(Generators[i], Dehomogenization) == 0) {
5877                 if (ToCompute.test(ConeProperty::Approximate) || ToCompute.test(ConeProperty::Projection) ||
5878                     ToCompute.test(ConeProperty::NumberLatticePoints))
5879                     throw NotComputableException(
5880                         "Approximation, Projection or NumberLatticePoints not applicable to unbounded polyhedra");
5881                 else
5882                     return;
5883             }
5884         }
5885     }
5886 
5887     if (!ToCompute.test(ConeProperty::Approximate))
5888         is_parallelotope = check_parallelotope();
5889 
5890     if (verbose && is_parallelotope)
5891         verboseOutput() << "Polyhedron is parallelotope" << endl;
5892 
5893     if (is_parallelotope) {
5894         SupportHyperplanes.remove_row(Dehomogenization);
5895         setComputed(ConeProperty::SupportHyperplanes);
5896         addition_constraints_allowed=true;
5897         setComputed(ConeProperty::MaximalSubspace);
5898         setComputed(ConeProperty::Sublattice);
5899         pointed = true;
5900         setComputed(ConeProperty::IsPointed);
5901         if (inhomogeneous) {
5902             affine_dim = dim - 1;
5903             setComputed(ConeProperty::AffineDim);
5904             recession_rank = 0;
5905             setComputed(ConeProperty::RecessionRank);
5906         }
5907     }
5908 
5909     ConeProperties NeededHere;
5910     NeededHere.set(ConeProperty::SupportHyperplanes);
5911     NeededHere.set(ConeProperty::Sublattice);
5912     NeededHere.set(ConeProperty::MaximalSubspace);
5913     if (inhomogeneous)
5914         NeededHere.set(ConeProperty::AffineDim);
5915     if (!inhomogeneous){
5916         NeededHere.set(ConeProperty::Grading);
5917         if(ToCompute.test(ConeProperty::NoGradingDenom))
5918             NeededHere.set(ConeProperty::NoGradingDenom);
5919     }
5920     try {
5921         compute(NeededHere);
5922     } catch (const NotComputableException& e)  // in case the grading does not exist -- will be found later
5923     {
5924     }
5925 
5926     if (!is_parallelotope && !ToCompute.test(ConeProperty ::Projection) && !ToCompute.test(ConeProperty::Approximate) &&
5927         SupportHyperplanes.nr_of_rows() > 100 * ExtremeRays.nr_of_rows())
5928         return;
5929 
5930     if (!is_parallelotope && !ToCompute.test(ConeProperty::Approximate)) {  // we try again
5931         is_parallelotope = check_parallelotope();
5932         if (is_parallelotope) {
5933             if (verbose)
5934                 verboseOutput() << "Polyhedron is parallelotope" << endl;
5935             SupportHyperplanes.remove_row(Dehomogenization);
5936             setComputed(ConeProperty::SupportHyperplanes);
5937             addition_constraints_allowed=true;
5938             setComputed(ConeProperty::MaximalSubspace);
5939             setComputed(ConeProperty::Sublattice);
5940             pointed = true;
5941             setComputed(ConeProperty::IsPointed);
5942             if (inhomogeneous) {
5943                 affine_dim = dim - 1;
5944                 setComputed(ConeProperty::AffineDim);
5945             }
5946         }
5947     }
5948 
5949     if (!is_parallelotope) {  // don't need them anymore
5950         Pair.clear();
5951         ParaInPair.clear();
5952     }
5953 
5954     if (inhomogeneous && affine_dim <= 0)
5955         return;
5956 
5957     if (!inhomogeneous && !isComputed(ConeProperty::Grading))
5958         return;
5959 
5960     if (!inhomogeneous && ToCompute.test(ConeProperty::Approximate) && GradingDenom != 1)
5961         return;
5962 
5963     if (!pointed || BasisChangePointed.getRank() == 0)
5964         return;
5965 
5966     if (inhomogeneous && !polytope_check_done) {
5967         for (size_t i = 0; i < Generators.nr_of_rows(); ++i) {
5968             if (v_scalar_product(Generators[i], Dehomogenization) == 0) {
5969                 if (ToCompute.test(ConeProperty::Approximate) || ToCompute.test(ConeProperty::Projection) ||
5970                     ToCompute.test(ConeProperty::NumberLatticePoints))
5971                     throw NotComputableException(
5972                         "Approximation, Projection or NumberLatticePoints not applicable to unbounded polyhedra");
5973                 else
5974                     return;
5975             }
5976         }
5977     }
5978 
5979     if (inhomogeneous) {  // exclude that dehomogenization has a gcd > 1
5980         vector<Integer> test_dehom = BasisChange.to_sublattice_dual_no_div(Dehomogenization);
5981         if (v_make_prime(test_dehom) != 1)
5982             return;
5983     }
5984 
5985     // ****************************************************************
5986     //
5987     // NOTE: THE FIRST COORDINATE IS (OR WILL BE MADE) THE GRADING !!!!
5988     //
5989     // ****************************************************************
5990 
5991     vector<Integer> GradForApprox;
5992     if (!inhomogeneous)
5993         GradForApprox = Grading;
5994     else {
5995         GradForApprox = Dehomogenization;
5996         GradingDenom = 1;
5997     }
5998 
5999     Grading_Is_Coordinate = false;
6000     size_t nr_nonzero = 0;
6001     for (size_t i = 0; i < dim; ++i) {
6002         if (GradForApprox[i] != 0) {
6003             nr_nonzero++;
6004             GradingCoordinate = i;
6005         }
6006     }
6007     if (nr_nonzero == 1) {
6008         if (GradForApprox[GradingCoordinate] == 1)
6009             Grading_Is_Coordinate = true;
6010     }
6011 
6012     Matrix<Integer> GradGen;
6013     if (Grading_Is_Coordinate) {
6014         if (!ToCompute.test(ConeProperty::Approximate)) {
6015             GradGen = Generators;
6016             GradGen.exchange_columns(0, GradingCoordinate);  // we swap it into the first coordinate
6017         }
6018         else {  // we swap the grading into the first coordinate and approximate
6019             GradGen.resize(0, dim);
6020             for (size_t i = 0; i < Generators.nr_of_rows(); ++i) {
6021                 vector<Integer> gg = Generators[i];
6022                 swap(gg[0], gg[GradingCoordinate]);
6023                 list<vector<Integer> > approx;
6024                 approx_simplex(gg, approx, 1);
6025                 GradGen.append(Matrix<Integer>(approx));
6026             }
6027         }
6028     }
6029     else {  // to avoid coordinate transformations, we prepend the degree as the first coordinate
6030         GradGen.resize(0, dim + 1);
6031         for (size_t i = 0; i < Generators.nr_of_rows(); ++i) {
6032             vector<Integer> gg(dim + 1);
6033             for (size_t j = 0; j < dim; ++j)
6034                 gg[j + 1] = Generators[i][j];
6035             gg[0] = v_scalar_product(Generators[i], GradForApprox);
6036             // cout << gg;
6037             if (ToCompute.test(ConeProperty::Approximate)) {
6038                 list<vector<Integer> > approx;
6039                 approx_simplex(gg, approx, 1);
6040                 GradGen.append(Matrix<Integer>(approx));
6041             }
6042             else
6043                 GradGen.append(gg);
6044         }
6045     }
6046 
6047     // data prepared, bow nthe computation
6048 
6049     Matrix<Integer> CongOri = BasisChange.getCongruencesMatrix();
6050     vector<Integer> GradingOnPolytope;  // used in the inhomogeneous case for Hilbert function
6051     if (inhomogeneous && isComputed(ConeProperty::Grading) && ToCompute.test(ConeProperty::HilbertSeries))
6052         GradingOnPolytope = Grading;
6053 
6054     Matrix<Integer> Raw(0, GradGen.nr_of_columns());  // result is returned in this matrix
6055 
6056     if (ToCompute.test(ConeProperty::Approximate)) {
6057         if (verbose)
6058             verboseOutput() << "Computing lattice points by approximation" << endl;
6059         Cone<Integer> HelperCone(InputType::cone, GradGen);
6060         HelperCone.ApproximatedCone =
6061             &(*this);                        // we will pass this information to the Full_Cone that computes the lattice points.
6062         HelperCone.is_approximation = true;  // It allows us to discard points outside *this as quickly as possible
6063         HelperCone.compute(ConeProperty::Deg1Elements, ConeProperty::PrimalMode);
6064         Raw = HelperCone.getDeg1ElementsMatrix();
6065     }
6066     else {
6067         if (verbose) {
6068             string activity = "Computing ";
6069             if (ToCompute.test(ConeProperty::NumberLatticePoints))
6070                 activity = "counting ";
6071             verboseOutput() << activity + "lattice points by project-and-lift" << endl;
6072         }
6073         Matrix<Integer> Supps, Equs, Congs;
6074         if (Grading_Is_Coordinate) {
6075             Supps = SupportHyperplanes;
6076             Supps.exchange_columns(0, GradingCoordinate);
6077             Equs = BasisChange.getEquationsMatrix();
6078             Equs.exchange_columns(0, GradingCoordinate);
6079             Congs = CongOri;
6080             Congs.exchange_columns(0, GradingCoordinate);
6081             if (GradingOnPolytope.size() > 0)
6082                 swap(GradingOnPolytope[0], GradingOnPolytope[GradingCoordinate]);
6083         }
6084         else {
6085             Supps = SupportHyperplanes;
6086             Supps.insert_column(0, 0);
6087             Equs = BasisChange.getEquationsMatrix();
6088             Equs.insert_column(0, 0);
6089             vector<Integer> ExtraEqu(Equs.nr_of_columns());
6090             ExtraEqu[0] = -1;
6091             for (size_t i = 0; i < Grading.size(); ++i)
6092                 ExtraEqu[i + 1] = Grading[i];
6093             Equs.append(ExtraEqu);
6094             Congs = CongOri;
6095             Congs.insert_column(0, 0);
6096             if (GradingOnPolytope.size() > 0) {
6097                 GradingOnPolytope.insert(GradingOnPolytope.begin(), 0);
6098             }
6099         }
6100         Supps.append(Equs);  // we must add the equations as pairs of inequalities
6101         Equs.scalar_multiplication(-1);
6102         Supps.append(Equs);
6103         project_and_lift(ToCompute, Raw, GradGen, Supps, Congs, GradingOnPolytope);
6104     }
6105 
6106     // computation done. It remains to restore the old coordinates
6107 
6108     HilbertBasis = Matrix<Integer>(0, dim);
6109     Deg1Elements = Matrix<Integer>(0, dim);
6110     ModuleGenerators = Matrix<Integer>(0, dim);
6111 
6112     if (Grading_Is_Coordinate)
6113         Raw.exchange_columns(0, GradingCoordinate);
6114 
6115     if (Grading_Is_Coordinate && CongOri.nr_of_rows() == 0) {
6116         if (inhomogeneous)
6117             ModuleGenerators.swap(Raw);
6118         else
6119             Deg1Elements.swap(Raw);
6120     }
6121     else {
6122         if (CongOri.nr_of_rows() > 0 && verbose && ToCompute.test(ConeProperty::Approximate))
6123             verboseOutput() << "Sieving lattice points by congruences" << endl;
6124         for (size_t i = 0; i < Raw.nr_of_rows(); ++i) {
6125             vector<Integer> rr;
6126             if (Grading_Is_Coordinate) {
6127                 swap(rr, Raw[i]);
6128             }
6129             else {
6130                 rr.resize(dim);  // remove the prepended grading
6131                 for (size_t j = 0; j < dim; ++j)
6132                     rr[j] = Raw[i][j + 1];
6133             }
6134             if (ToCompute.test(ConeProperty::Approximate) &&
6135                 !CongOri.check_congruences(rr))  // already checked with project_and_lift
6136                 continue;
6137             if (inhomogeneous) {
6138                 ModuleGenerators.append(rr);
6139             }
6140             else
6141                 Deg1Elements.append(rr);
6142         }
6143     }
6144 
6145     setWeights();
6146     if (inhomogeneous)
6147         ModuleGenerators.sort_by_weights(WeightsGrad, GradAbs);
6148     else
6149         Deg1Elements.sort_by_weights(WeightsGrad, GradAbs);
6150 
6151     if (!ToCompute.test(ConeProperty::NumberLatticePoints)) {
6152         if (!inhomogeneous)
6153             number_lattice_points = Deg1Elements.nr_of_rows();
6154         else
6155             number_lattice_points = ModuleGenerators.nr_of_rows();
6156     }
6157 
6158     setComputed(ConeProperty::NumberLatticePoints);  // always computed
6159     if (!inhomogeneous &&
6160         !ToCompute.test(ConeProperty::Deg1Elements))  // we have only counted, nothing more possible in the hom case
6161         return;
6162 
6163     if (inhomogeneous) {  // as in convert_polyhedron_to polytope of full_cone.cpp
6164 
6165         module_rank = number_lattice_points;
6166         setComputed(ConeProperty::ModuleRank);
6167         recession_rank = 0;
6168         setComputed(ConeProperty::RecessionRank);
6169 
6170         if (ToCompute.test(ConeProperty::HilbertBasis)) {  // we have computed the lattice points and not only counted them
6171             setComputed(ConeProperty::HilbertBasis);
6172             setComputed(ConeProperty::ModuleGenerators);
6173         }
6174 
6175         if (isComputed(ConeProperty::Grading)) {
6176             multiplicity = static_cast<unsigned long>(module_rank);  // of the recession cone;
6177             setComputed(ConeProperty::Multiplicity);
6178             if (ToCompute.test(ConeProperty::HilbertSeries) &&
6179                 ToCompute.test(ConeProperty::Approximate)) {  // already done with project_and_lift
6180                 try_Hilbert_Series_from_lattice_points(ToCompute);
6181             }
6182         }
6183     }
6184     else
6185         setComputed(ConeProperty::Deg1Elements);
6186 
6187     // setComputed(ConeProperty::Approximate);
6188 
6189     return;
6190 }
6191 
6192 //---------------------------------------------------------------------------
6193 template <typename Integer>
project_and_lift(const ConeProperties & ToCompute,Matrix<Integer> & Deg1,const Matrix<Integer> & Gens,const Matrix<Integer> & Supps,const Matrix<Integer> & Congs,const vector<Integer> GradingOnPolytope)6194 void Cone<Integer>::project_and_lift(const ConeProperties& ToCompute,
6195                                      Matrix<Integer>& Deg1,
6196                                      const Matrix<Integer>& Gens,
6197                                      const Matrix<Integer>& Supps,
6198                                      const Matrix<Integer>& Congs,
6199                                      const vector<Integer> GradingOnPolytope) {
6200     bool float_projection = ToCompute.test(ConeProperty::ProjectionFloat);
6201     bool count_only = ToCompute.test(ConeProperty::NumberLatticePoints);
6202 
6203     vector<dynamic_bitset> Ind;
6204 
6205     if (!is_parallelotope) {
6206         Ind = vector<dynamic_bitset>(Supps.nr_of_rows(), dynamic_bitset(Gens.nr_of_rows()));
6207         for (size_t i = 0; i < Supps.nr_of_rows(); ++i)
6208             for (size_t j = 0; j < Gens.nr_of_rows(); ++j)
6209                 if (v_scalar_product(Supps[i], Gens[j]) == 0)
6210                     Ind[i][j] = true;
6211     }
6212 
6213     size_t rank = BasisChangePointed.getRank();
6214 
6215     Matrix<Integer> Verts;
6216     if (isComputed(ConeProperty::Generators)) {
6217         vector<key_t> choice = identity_key(Gens.nr_of_rows());  // Gens.max_rank_submatrix_lex();
6218         if (choice.size() >= dim)
6219             Verts = Gens.submatrix(choice);
6220     }
6221 
6222     vector<num_t> h_vec_pos, h_vec_neg;
6223 
6224     if (float_projection) {  // conversion to float inside project-and-lift
6225         // vector<Integer> Dummy;
6226         ProjectAndLift<Integer, MachineInteger> PL;
6227         if (!is_parallelotope)
6228             PL = ProjectAndLift<Integer, MachineInteger>(Supps, Ind, rank);
6229         else
6230             PL = ProjectAndLift<Integer, MachineInteger>(Supps, Pair, ParaInPair, rank);
6231         Matrix<MachineInteger> CongsMI;
6232         convert(CongsMI, Congs);
6233         PL.set_congruences(CongsMI);
6234         PL.set_grading_denom(convertTo<MachineInteger>(GradingDenom));
6235         vector<MachineInteger> GOPMI;
6236         convert(GOPMI, GradingOnPolytope);
6237         PL.set_grading(GOPMI);
6238         PL.set_verbose(verbose);
6239         PL.set_LLL(!ToCompute.test(ConeProperty::NoLLL));
6240         PL.set_no_relax(ToCompute.test(ConeProperty::NoRelax));
6241         PL.set_vertices(Verts);
6242         PL.compute(true, true, count_only);  // the first true for all_points, the second for float
6243         Matrix<MachineInteger> Deg1MI(0, Deg1.nr_of_columns());
6244         PL.put_eg1Points_into(Deg1MI);
6245         convert(Deg1, Deg1MI);
6246         number_lattice_points = PL.getNumberLatticePoints();
6247         PL.get_h_vectors(h_vec_pos, h_vec_neg);
6248     }
6249     else {
6250         if (change_integer_type) {
6251             Matrix<MachineInteger> Deg1MI(0, Deg1.nr_of_columns());
6252             // Matrix<MachineInteger> GensMI;
6253             Matrix<MachineInteger> SuppsMI;
6254             try {
6255                 // convert(GensMI,Gens);
6256                 convert(SuppsMI, Supps);
6257                 MachineInteger GDMI = convertTo<MachineInteger>(GradingDenom);
6258                 ProjectAndLift<MachineInteger, MachineInteger> PL;
6259                 if (!is_parallelotope)
6260                     PL = ProjectAndLift<MachineInteger, MachineInteger>(SuppsMI, Ind, rank);
6261                 else
6262                     PL = ProjectAndLift<MachineInteger, MachineInteger>(SuppsMI, Pair, ParaInPair, rank);
6263                 Matrix<MachineInteger> CongsMI;
6264                 convert(CongsMI, Congs);
6265                 PL.set_congruences(CongsMI);
6266                 PL.set_grading_denom(GDMI);
6267                 vector<MachineInteger> GOPMI;
6268                 convert(GOPMI, GradingOnPolytope);
6269                 PL.set_grading(GOPMI);
6270                 PL.set_verbose(verbose);
6271                 PL.set_no_relax(ToCompute.test(ConeProperty::NoRelax));
6272                 PL.set_LLL(!ToCompute.test(ConeProperty::NoLLL));
6273                 Matrix<MachineInteger> VertsMI;
6274                 convert(VertsMI, Verts);
6275                 PL.set_vertices(VertsMI);
6276                 PL.compute(true, false, count_only);
6277                 PL.put_eg1Points_into(Deg1MI);
6278                 number_lattice_points = PL.getNumberLatticePoints();
6279                 PL.get_h_vectors(h_vec_pos, h_vec_neg);
6280             } catch (const ArithmeticException& e) {
6281                 if (verbose) {
6282                     verboseOutput() << e.what() << endl;
6283                     verboseOutput() << "Restarting with a bigger type." << endl;
6284                 }
6285                 change_integer_type = false;
6286             }
6287             if (change_integer_type) {
6288                 convert(Deg1, Deg1MI);
6289             }
6290         }
6291 
6292         if (!change_integer_type) {
6293             ProjectAndLift<Integer, Integer> PL;
6294             if (!is_parallelotope)
6295                 PL = ProjectAndLift<Integer, Integer>(Supps, Ind, rank);
6296             else
6297                 PL = ProjectAndLift<Integer, Integer>(Supps, Pair, ParaInPair, rank);
6298             PL.set_congruences(Congs);
6299             PL.set_grading_denom(GradingDenom);
6300             PL.set_grading(GradingOnPolytope);
6301             PL.set_verbose(verbose);
6302             PL.set_no_relax(ToCompute.test(ConeProperty::NoRelax));
6303             PL.set_LLL(!ToCompute.test(ConeProperty::NoLLL));
6304             PL.set_vertices(Verts);
6305             PL.compute(true, false, count_only);
6306             PL.put_eg1Points_into(Deg1);
6307             number_lattice_points = PL.getNumberLatticePoints();
6308             PL.get_h_vectors(h_vec_pos, h_vec_neg);
6309         }
6310     }
6311 
6312     if (ToCompute.test(ConeProperty::HilbertSeries) && isComputed(ConeProperty::Grading)) {
6313         make_Hilbert_series_from_pos_and_neg(h_vec_pos, h_vec_neg);
6314     }
6315 
6316     /* setComputed(ConeProperty::Projection);
6317     if(ToCompute.test(ConeProperty::NoRelax))
6318         setComputed(ConeProperty::NoRelax);
6319     if(ToCompute.test(ConeProperty::NoLLL))
6320         setComputed(ConeProperty::NoLLL);
6321     if(float_projection)
6322         setComputed(ConeProperty::ProjectionFloat);*/
6323 
6324     if (verbose)
6325         verboseOutput() << "Project-and-lift complete" << endl
6326                         << "------------------------------------------------------------" << endl;
6327 }
6328 
6329 //---------------------------------------------------------------------------
6330 template <typename Integer>
check_parallelotope()6331 bool Cone<Integer>::check_parallelotope() {
6332     if (dim <= 1)
6333         return false;
6334 
6335     vector<Integer> Grad;  // copy of Grading or Dehomogenization
6336 
6337     if (inhomogeneous) {
6338         Grad = Dehomogenization;
6339     }
6340     else {
6341         if (!isComputed(ConeProperty::Grading))
6342             return false;
6343         Grad = Grading;
6344     }
6345 
6346     Grading_Is_Coordinate = false;
6347     size_t nr_nonzero = 0;
6348     for (size_t i = 0; i < Grad.size(); ++i) {
6349         if (Grad[i] != 0) {
6350             nr_nonzero++;
6351             GradingCoordinate = i;
6352         }
6353     }
6354     if (nr_nonzero == 1) {
6355         if (Grad[GradingCoordinate] == 1)
6356             Grading_Is_Coordinate = true;
6357     }
6358     if (!Grading_Is_Coordinate)
6359         return false;
6360     if (Equations.nr_of_rows() > 0)
6361         return false;
6362 
6363     SupportHyperplanes.sort_lex();
6364 
6365     Matrix<Integer> Supps(SupportHyperplanes);
6366     if (inhomogeneous)
6367         Supps.remove_row(Grad);
6368 
6369     size_t dim = Supps.nr_of_columns() - 1;  // affine dimension
6370     if (Supps.nr_of_rows() != 2 * dim)
6371         return false;
6372     Pair.resize(2 * dim);
6373     ParaInPair.resize(2 * dim);
6374     for (size_t i = 0; i < 2 * dim; ++i) {
6375         Pair[i].resize(dim);
6376         Pair[i].reset();
6377         ParaInPair[i].resize(dim);
6378         ParaInPair[i].reset();
6379     }
6380 
6381     vector<bool> done(2 * dim);
6382     Matrix<Integer> M2(2, dim + 1), M3(3, dim + 1);
6383     M3[2] = Grad;
6384     size_t pair_counter = 0;
6385 
6386     vector<key_t> Supp_1;  // to find antipodal vertices
6387     vector<key_t> Supp_2;
6388 
6389     for (size_t i = 0; i < 2 * dim; ++i) {
6390         if (done[i])
6391             continue;
6392         bool parallel_found = false;
6393         M2[0] = Supps[i];
6394         M3[0] = Supps[i];
6395         size_t j = i + 1;
6396         for (; j < 2 * dim; ++j) {
6397             if (done[j])
6398                 continue;
6399             M2[1] = Supps[j];
6400             if (M2.rank() < 2)
6401                 continue;
6402             M3[1] = Supps[j];
6403             if (M3.rank() == 3)
6404                 continue;
6405             else {
6406                 parallel_found = true;
6407                 done[j] = true;
6408                 break;
6409             }
6410         }
6411         if (!parallel_found)
6412             return false;
6413         Supp_1.push_back(i);
6414         Supp_2.push_back(j);
6415         Pair[i][pair_counter] = true;        // Pair[i] indicates to which pair of parallel facets rge facet i belongs
6416         Pair[j][pair_counter] = true;        // ditto for face j
6417         ParaInPair[j][pair_counter] = true;  // face i is "distinguished" and gace j is its parallel (and marked as such)
6418         pair_counter++;
6419     }
6420 
6421     Matrix<Integer> v1 = Supps.submatrix(Supp_1).kernel(false);  // opposite vertices
6422     Matrix<Integer> v2 = Supps.submatrix(Supp_2).kernel(false);
6423     Integer MinusOne = -1;
6424     if (v_scalar_product(v1[0], Grad) == 0)
6425         return false;
6426     if (v_scalar_product(v2[0], Grad) == 0)
6427         return false;
6428     if (v_scalar_product(v1[0], Grad) < 0)
6429         v_scalar_multiplication(v1[0], MinusOne);
6430     if (v_scalar_product(v2[0], Grad) < 0)
6431         v_scalar_multiplication(v2[0], MinusOne);
6432     if (v1.nr_of_rows() != 1 || v2.nr_of_rows() != 1)
6433         return false;
6434     for (unsigned int& i : Supp_1) {
6435         if (!(v_scalar_product(Supps[i], v2[0]) > 0))
6436             return false;
6437     }
6438     for (unsigned int& i : Supp_2) {
6439         if (!(v_scalar_product(Supps[i], v1[0]) > 0))
6440             return false;
6441     }
6442 
6443     // we have found opposite vertices
6444 
6445     return true;
6446 }
6447 
6448 //---------------------------------------------------------------------------
6449 template <typename Integer>
compute_volume(ConeProperties & ToCompute)6450 void Cone<Integer>::compute_volume(ConeProperties& ToCompute) {
6451     if (!ToCompute.test(ConeProperty::Volume))
6452         return;
6453     if (!inhomogeneous) {
6454         if (BasisMaxSubspace.nr_of_rows() > 0)
6455             throw NotComputableException("Volume not computable for polyhedra containing an affine space of dim > 0");
6456         volume = multiplicity;
6457         setComputed(ConeProperty::Volume);
6458         euclidean_volume = mpq_to_nmz_float(volume) * euclidean_corr_factor();
6459         setComputed(ConeProperty::EuclideanVolume);
6460         return;
6461     }
6462 
6463     /*
6464     compute(ConeProperty::Generators);
6465     compute(ConeProperty::AffineDim);
6466 
6467     if (affine_dim <= 0) {
6468         if (affine_dim == -1) {
6469             volume = 0;
6470             euclidean_volume = 0;
6471         }
6472         else {
6473             volume = 1;
6474             euclidean_volume = 1.0;
6475         }
6476         setComputed(ConeProperty::Volume);
6477         setComputed(ConeProperty::EuclideanVolume);
6478         return;
6479     }
6480 
6481     if (BasisMaxSubspace.nr_of_rows() > 0)
6482         throw NotComputableException("Volume not computable for polyhedra containing an affine space of dim > 0");
6483 
6484     for (size_t i = 0; i < Generators.nr_of_rows(); ++i) {
6485         if (v_scalar_product(Generators[i], Dehomogenization) == 0)
6486             throw NotComputableException("Volume not computable for unbounded polyhedra");
6487     }
6488     map<InputType, Matrix<Integer> > DefVolCone;
6489     if (!BasisChangePointed.IsIdentity())
6490         DefVolCone[Type::lattice] = get_sublattice_internal().getEmbeddingMatrix();
6491     DefVolCone[Type::grading] = Dehomogenization;
6492     if (isComputed(ConeProperty::SupportHyperplanes))
6493         DefVolCone[Type::inequalities] = SupportHyperplanes;
6494     if (isComputed(ConeProperty::ExtremeRays))
6495         DefVolCone[Type::cone] = VerticesOfPolyhedron;
6496     else
6497         DefVolCone[Type::cone] = Generators;
6498     Cone<Integer> VolCone(DefVolCone);
6499     if (ToCompute.test(ConeProperty::Descent))
6500         VolCone.compute(ConeProperty::Volume, ConeProperty::Descent);
6501     if (ToCompute.test(ConeProperty::SignedDec))
6502         VolCone.compute(ConeProperty::Volume, ConeProperty::SignedDec);
6503     else {
6504         if (ToCompute.test(ConeProperty::NoDescent))
6505             VolCone.compute(ConeProperty::Volume, ConeProperty::NoDescent);
6506         else
6507             VolCone.compute(ConeProperty::Volume);
6508     }
6509     volume = VolCone.getVolume();
6510     euclidean_volume = VolCone.getEuclideanVolume();
6511     setComputed(ConeProperty::Volume);
6512     setComputed(ConeProperty::EuclideanVolume);
6513     return; */
6514 }
6515 
6516 //---------------------------------------------------------------------------
6517 template <typename Integer>
euclidean_corr_factor()6518 nmz_float Cone<Integer>::euclidean_corr_factor() {
6519     // Though this function can now only be called with GradingDenom=1
6520     // but variable not yet removed
6521     // In the inhomogeneous case we may have to set it:
6522 
6523     if (get_rank_internal() - BasisMaxSubspace.nr_of_rows() == 0)
6524         return 1.0;
6525 
6526     Integer GradingDenom = 1;
6527 
6528     vector<Integer> Grad;
6529     if (inhomogeneous)
6530         Grad = Dehomogenization;
6531     else
6532         Grad = Grading;
6533 
6534     // First we find a simplex in our space as quickly as possible
6535 
6536     Matrix<Integer> Simplex = BasisChangePointed.getEmbeddingMatrix();
6537     // Matrix<Integer> Simplex=Generators.submatrix(Generators.max_rank_submatrix_lex()); -- numerically bad !!!!
6538     size_t n = Simplex.nr_of_rows();
6539     vector<Integer> raw_degrees = Simplex.MxV(Grad);
6540 
6541     size_t non_zero = 0;
6542     for (size_t i = 0; i < raw_degrees.size(); ++i)
6543         if (raw_degrees[i] != 0) {
6544             non_zero = i;
6545             break;
6546         }
6547 
6548     Integer MinusOne = -1;
6549     if (raw_degrees[non_zero] < 0){
6550         v_scalar_multiplication(Simplex[non_zero], MinusOne);  // makes this degree > 0
6551         raw_degrees[non_zero]*=-1;
6552     }
6553     for (size_t i = 0; i < n; ++i) {
6554         if (raw_degrees[i] == 0)
6555             Simplex[i] = v_add(Simplex[i], Simplex[non_zero]);  // makes this degree > 0
6556         if (raw_degrees[i] < 0)
6557             v_scalar_multiplication(Simplex[i], MinusOne);  // ditto
6558     }
6559 
6560     vector<Integer> degrees = Simplex.MxV(Grad);
6561 
6562     // we compute the lattice normalized volume and later the euclidean volume
6563     // of the simplex defined by Simplex to get the correction factor
6564     Cone<Integer> VolCone(Type::cone, Simplex, Type::lattice, get_sublattice_internal().getEmbeddingMatrix(), Type::grading,
6565                           Matrix<Integer>(Grad));
6566     VolCone.setVerbose(false);
6567     ConeProperties VolComp;
6568     VolComp.set(ConeProperty::Multiplicity);
6569     VolComp.set(ConeProperty::NoBottomDec);
6570     VolComp.set(ConeProperty::NoGradingDenom);
6571     VolComp.set(ConeProperty::NoDescent);
6572     VolComp.set(ConeProperty::NoSignedDec);
6573     VolCone.compute(VolComp);
6574     mpq_class norm_vol_simpl = VolCone.getMultiplicity();
6575     // lattice normalized volume of our Simplex
6576 
6577     // now the euclidean volume
6578     Matrix<nmz_float> Bas;
6579     convert(Bas, Simplex);
6580     for (size_t i = 0; i < n; ++i) {
6581         v_scalar_division(Bas[i], convertTo<nmz_float>(degrees[i]));
6582         v_scalar_multiplication(Bas[i], convertTo<nmz_float>(GradingDenom));
6583     }
6584     // choose an origin, namely Bas[0]
6585     Matrix<nmz_float> Bas1(n - 1, dim);
6586     for (size_t i = 1; i < n; ++i)
6587         for (size_t j = 0; j < dim; ++j)
6588             Bas1[i - 1][j] = Bas[i][j] - Bas[0][j];
6589 
6590     // orthogonalize Bas1
6591     Matrix<double> G(n, dim);
6592     Matrix<double> M(n, n);
6593     Bas1.GramSchmidt(G, M, 0, n - 1);
6594     // compute euclidean volume
6595     nmz_float eucl_vol_simpl = 1;
6596     for (size_t i = 0; i < n - 1; ++i)
6597         eucl_vol_simpl *= sqrt(v_scalar_product(G[i], G[i]));
6598     // so far the euclidean volume of the paralleotope
6599     nmz_float fact;
6600     convert(fact, nmz_factorial((long)n - 1));
6601     // now the volume of the simplex
6602     eucl_vol_simpl /= fact;
6603 
6604     // now the correction
6605     nmz_float corr_factor = eucl_vol_simpl / mpq_to_nmz_float(norm_vol_simpl);
6606     return corr_factor;
6607 }
6608 
6609 //---------------------------------------------------------------------------
6610 template <typename Integer>
compute_projection(ConeProperties & ToCompute)6611 void Cone<Integer>::compute_projection(ConeProperties& ToCompute) {
6612     if (!ToCompute.test(ConeProperty::ProjectCone))
6613         return;
6614 
6615     if (projection_coord_indicator.size() == 0)
6616         throw BadInputException("input projection_coordinates not set");
6617 
6618     if (projection_coord_indicator == vector<bool>(dim))
6619         throw BadInputException("Projection to zero coordinates make no sense");
6620 
6621     if (projection_coord_indicator == vector<bool>(dim, true))
6622         throw BadInputException("Projection to all coordinates make no sense");
6623 
6624     vector<Integer> GradOrDehom, GradOrDehomProj;
6625     if (inhomogeneous)
6626         GradOrDehom = Dehomogenization;
6627     else if (isComputed(ConeProperty::Grading))
6628         GradOrDehom = Grading;
6629     for (size_t i = 0; i < GradOrDehom.size(); ++i) {
6630         if (!projection_coord_indicator[i]) {
6631             if (GradOrDehom[i] != 0)
6632                 throw BadInputException("Grading or Dehomogenization not compatible with projection");
6633         }
6634         else
6635             GradOrDehomProj.push_back(GradOrDehom[i]);
6636     }
6637 
6638     if (isComputed(ConeProperty::Generators))
6639         compute_projection_from_gens(GradOrDehomProj);
6640     else
6641         compute_projection_from_constraints(GradOrDehomProj, ToCompute);
6642 
6643     setComputed(ConeProperty::ProjectCone);
6644 }
6645 //---------------------------------------------------------------------------
6646 template <typename Integer>
compute_projection_from_gens(const vector<Integer> & GradOrDehomProj)6647 void Cone<Integer>::compute_projection_from_gens(const vector<Integer>& GradOrDehomProj) {
6648     Matrix<Integer> GensProj = Generators.select_columns(projection_coord_indicator);
6649     map<InputType, Matrix<Integer> > ProjInput;
6650     ProjInput[Type::cone] = GensProj;
6651     if (GradOrDehomProj.size() > 0) {
6652         if (inhomogeneous)
6653             ProjInput[Type::dehomogenization] = GradOrDehomProj;
6654         else
6655             ProjInput[Type::grading] = GradOrDehomProj;
6656     }
6657 
6658     if(ProjCone != NULL)
6659         delete ProjCone;
6660 
6661     ProjCone = new Cone<Integer>(ProjInput);
6662     if (verbose)
6663         verboseOutput() << "Computing projection from generators" << endl;
6664     ProjCone->compute(ConeProperty::SupportHyperplanes);
6665 }
6666 
6667 //---------------------------------------------------------------------------
6668 template <typename Integer>
compute_projection_from_constraints(const vector<Integer> & GradOrDehomProj,ConeProperties & ToCompute)6669 void Cone<Integer>::compute_projection_from_constraints(const vector<Integer>& GradOrDehomProj, ConeProperties& ToCompute) {
6670     compute_generators(ToCompute);
6671     Matrix<Integer> Gens = Generators.selected_columns_first(projection_coord_indicator);
6672     Matrix<Integer> ReorderedBasis = BasisMaxSubspace.selected_columns_first(projection_coord_indicator);
6673     Gens.append(ReorderedBasis);
6674 
6675     Matrix<Integer> Supps = SupportHyperplanes.selected_columns_first(projection_coord_indicator);
6676     Matrix<Integer> ReorderedEquations = BasisChange.getEquationsMatrix().selected_columns_first(projection_coord_indicator);
6677     Supps.append(ReorderedEquations);
6678     Integer MinusOne = -1;
6679     ReorderedEquations.scalar_multiplication(MinusOne);
6680     Supps.append(ReorderedEquations);
6681 
6682     vector<dynamic_bitset> Ind;
6683 
6684     Ind = vector<dynamic_bitset>(Supps.nr_of_rows(), dynamic_bitset(Gens.nr_of_rows()));
6685     for (size_t i = 0; i < Supps.nr_of_rows(); ++i)
6686         for (size_t j = 0; j < Gens.nr_of_rows(); ++j)
6687             if (v_scalar_product(Supps[i], Gens[j]) == 0)
6688                 Ind[i][j] = true;
6689 
6690     size_t proj_dim = 0;
6691     for (size_t i = 0; i < projection_coord_indicator.size(); ++i)
6692         if (projection_coord_indicator[i])
6693             proj_dim++;
6694 
6695     ProjectAndLift<Integer, Integer> PL;
6696     PL = ProjectAndLift<Integer, Integer>(Supps, Ind, BasisChangePointed.getRank());
6697     if (verbose)
6698         verboseOutput() << "Computing constraints of projection" << endl;
6699     PL.set_verbose(verbose);
6700     PL.compute_only_projection(proj_dim);
6701     Matrix<Integer> SuppsProj, EqusProj;
6702     PL.putSuppsAndEqus(SuppsProj, EqusProj, proj_dim);
6703     if (SuppsProj.nr_of_rows() == 0)
6704         SuppsProj.append(vector<Integer>(SuppsProj.nr_of_columns(), 0));  // to avoid completely empty input matrices
6705 
6706     map<InputType, Matrix<Integer> > ProjInput;
6707     if (GradOrDehomProj.size() > 0) {
6708         if (inhomogeneous)
6709             ProjInput[Type::dehomogenization] = GradOrDehomProj;
6710         else
6711             ProjInput[Type::grading] = GradOrDehomProj;
6712     }
6713     ProjInput[Type::inequalities] = SuppsProj;
6714     ProjInput[Type::equations] = EqusProj;
6715 
6716     Matrix<Integer> GensProj = Generators.select_columns(projection_coord_indicator);
6717     Matrix<Integer> BasHelp = BasisMaxSubspace.select_columns(projection_coord_indicator);
6718     GensProj.append(BasHelp);
6719     BasHelp.scalar_multiplication(MinusOne);
6720     GensProj.append(BasHelp);
6721     ProjInput[Type::cone] = GensProj;
6722 
6723     ProjCone = new Cone<Integer>(ProjInput);
6724     ProjCone->setRenf(RenfSharedPtr);
6725     ProjCone->compute(ConeProperty::SupportHyperplanes, ConeProperty::ExtremeRays);
6726 }
6727 
6728 #ifdef ENFNORMALIZ
6729 template <>
compute_projection_from_constraints(const vector<renf_elem_class> & GradOrDehomProj,ConeProperties & ToCompute)6730 void Cone<renf_elem_class>::compute_projection_from_constraints(const vector<renf_elem_class>& GradOrDehomProj,
6731                                                                 ConeProperties& ToCompute) {
6732     assert(false);
6733 }
6734 #endif
6735 
6736 //---------------------------------------------------------------------------
6737 
6738 template <typename Integer>
try_signed_dec(ConeProperties & ToCompute)6739 void Cone<Integer>::try_signed_dec(ConeProperties& ToCompute) {
6740 
6741     if(inhomogeneous) // in this case multiplicity defined algebraically, not as the volume of a polytope
6742         return;
6743 
6744     if(using_renf<Integer>()) // not yet implemented for renf
6745         return;
6746 
6747     bool something_to_do =   (!isComputed(ConeProperty::Multiplicity) && ToCompute.test(ConeProperty::Multiplicity))
6748                           || (!isComputed(ConeProperty::Integral) && ToCompute.test(ConeProperty::Integral))
6749                           || (!isComputed(ConeProperty::VirtualMultiplicity) && ToCompute.test(ConeProperty::VirtualMultiplicity));
6750 
6751     if(!something_to_do)
6752         return;
6753 
6754     bool do_integral = ToCompute.test(ConeProperty::Integral) || ToCompute.test(ConeProperty::VirtualMultiplicity);
6755 
6756     if(ToCompute.test(ConeProperty::NoSignedDec) || ToCompute.test(ConeProperty::Descent)
6757                   || ToCompute.test(ConeProperty::Symmetrize) ) // user wants something different
6758         return;
6759 
6760     bool do_multiplicity_differently = false;
6761 
6762     if ( (ToCompute.test(ConeProperty::HilbertSeries) || ToCompute.test(ConeProperty::WeightedEhrhartSeries) ||
6763         ToCompute.test(ConeProperty::VirtualMultiplicity) || ToCompute.test(ConeProperty::Integral) ||
6764         ToCompute.test(ConeProperty::Triangulation) || ToCompute.test(ConeProperty::StanleyDec) ||
6765         ToCompute.test(ConeProperty::TriangulationDetSum) || ToCompute.test(ConeProperty::TriangulationSize))
6766         && !do_integral)
6767             do_multiplicity_differently =true; // casws in which we must use an ordinary triangulation
6768 
6769     if(do_multiplicity_differently && !do_integral)
6770         return;
6771 
6772     if (!ToCompute.test(ConeProperty::SignedDec)) {  // we use Descent by default if there are not too many facets
6773         if (SupportHyperplanes.nr_of_rows() > 2 * dim + 1 ||
6774             SupportHyperplanes.nr_of_rows() <= BasisChangePointed.getRank())
6775             return;
6776     }
6777 
6778     if(SupportHyperplanes.nr_of_rows() == 0){
6779         compute(ConeProperty::SupportHyperplanes);
6780         ToCompute.reset(is_Computed);
6781     }
6782 
6783     if(!ToCompute.test(ConeProperty::SignedDec) && Generators.nr_of_rows() > 0 && Generators.nr_of_rows() < dim*SupportHyperplanes.nr_of_rows()/3)
6784         return; // ordinary triangulation can be expected to be faster
6785 
6786    if(BasisChangePointed.getRank() == 0){ // we want to go through full_cone
6787         return;
6788     }
6789 
6790     if(ToCompute.test(ConeProperty::NoGradingDenom))
6791         compute(ConeProperty::Grading, ConeProperty::NoGradingDenom);
6792     else
6793         compute(ConeProperty::Grading);
6794     ToCompute.reset(is_Computed);
6795 
6796     if(ToCompute.test(ConeProperty::SupportHyperplanes) || ToCompute.test(ConeProperty::ExtremeRays)|| do_integral){
6797         compute_generators(ToCompute);
6798         ToCompute.reset(is_Computed);
6799     }
6800 
6801     if(!ToCompute.test(ConeProperty::SignedDec) && Generators.nr_of_rows() > 0 && Generators.nr_of_rows() < dim*SupportHyperplanes.nr_of_rows()/3)
6802         return; // ordinary triangulation can be expected to be faster
6803 
6804     if(do_integral){
6805         if (BasisMaxSubspace.nr_of_rows() > 0)
6806                 throw NotComputableException("Integral not computable for polyhedra containing an affine space of dim > 0");
6807         if (IntData.getPolynomial() == "")
6808             throw BadInputException("Polynomial weight missing");
6809     }
6810 
6811     if(verbose)
6812         verboseOutput() << "Working with dual cone" << endl;
6813 
6814     if(change_integer_type){
6815         try{
6816             try_signed_dec_inner<MachineInteger>(ToCompute);
6817         } catch (const ArithmeticException& e) {
6818             if (verbose) {
6819                 verboseOutput() << e.what() << endl;
6820                 verboseOutput() << "Restarting with a bigger type." << endl;
6821             }
6822             change_integer_type = false;
6823         }
6824     }
6825 
6826     if(!change_integer_type)
6827         try_signed_dec_inner<Integer>(ToCompute);
6828 
6829 }
6830 
6831 template <typename Integer>
6832 template <typename IntegerFC>
try_signed_dec_inner(ConeProperties & ToCompute)6833 void Cone<Integer>::try_signed_dec_inner(ConeProperties& ToCompute) {
6834 
6835     Matrix<IntegerFC> SupphypEmb;
6836     BasisChangePointed.convert_to_sublattice_dual(SupphypEmb,SupportHyperplanes);
6837     Full_Cone<IntegerFC> Dual(SupphypEmb);
6838     Dual.verbose = verbose;
6839     if(ToCompute.test(ConeProperty::FixedPrecision)){
6840         if(decimal_digits > 0)
6841             Dual.decimal_digits = decimal_digits;
6842         else
6843             Dual.decimal_digits = 100;
6844         setComputed(ConeProperty::FixedPrecision);
6845     }
6846     if(ToCompute.test(ConeProperty::DistributedComp)){
6847         block_size_hollow_tri = 500000;
6848     }
6849     Dual.block_size_hollow_tri = block_size_hollow_tri; // for backward compatibility it is enough
6850     Dual.project_name = project_name;                   // to set block_size_hollow_tri;
6851     if(ToCompute.test(ConeProperty::NoGradingDenom))
6852          BasisChangePointed.convert_to_sublattice_dual_no_div(Dual.GradingOnPrimal, Grading);
6853     else
6854          BasisChangePointed.convert_to_sublattice_dual(Dual.GradingOnPrimal, Grading);
6855     if(ToCompute.test(ConeProperty::Multiplicity))
6856         Dual.do_multiplicity_by_signed_dec=true;
6857     if(ToCompute.test(ConeProperty::Integral))
6858         Dual.do_integral_by_signed_dec=true;
6859     if(ToCompute.test(ConeProperty::VirtualMultiplicity))
6860         Dual.do_virtual_multiplicity_by_signed_dec=true;
6861     if(ToCompute.test(ConeProperty::Integral) || ToCompute.test(ConeProperty::VirtualMultiplicity)){
6862         Dual.Polynomial = getIntData().getPolynomial();
6863         if(!BasisChangePointed.IsIdentity())
6864             convert(Dual.Embedding,BasisChangePointed.getEmbeddingMatrix());
6865     }
6866 
6867 
6868     if(ToCompute.test(ConeProperty::SupportHyperplanes))
6869         Dual.include_dualization= true;
6870 
6871     Dual.compute();
6872 
6873     if(Dual.isComputed(ConeProperty::Multiplicity)){
6874         if(Dual.multiplicity == 0){
6875             if(verbose){
6876                 verboseOutput() << "SignedDec applied to polytope embedded into higher dimensional space." << endl;
6877                 verboseOutput() << "Will be repeated after re-embdiing of polytope." << endl;
6878             }
6879             compute_generators(ToCompute);
6880             try_signed_dec_inner<IntegerFC>(ToCompute);
6881             return;
6882         }
6883 
6884         multiplicity = Dual.multiplicity;
6885         setComputed(ConeProperty::Multiplicity);
6886     }
6887     else{
6888         if(ToCompute.test(ConeProperty::Multiplicity))
6889             throw NotComputableException("Multiplicty not computable by signed decomposition");
6890     }
6891 
6892     if(Dual.isComputed(ConeProperty::Integral)){
6893         Integral=Dual.Integral;
6894         getIntData().setIntegral(Dual.Integral);
6895         nmz_float help = Dual.RawEuclideanIntegral;
6896         help *= euclidean_corr_factor();
6897         getIntData().setEuclideanIntegral(help);
6898         setComputed(ConeProperty::Integral);
6899         setComputed(ConeProperty::EuclideanIntegral);
6900     }
6901     if(Dual.isComputed(ConeProperty::VirtualMultiplicity)){
6902         VirtualMultiplicity = Dual.VirtualMultiplicity;
6903         getIntData().setVirtualMultiplicity(Dual.VirtualMultiplicity);
6904         setComputed(ConeProperty::VirtualMultiplicity);
6905     }
6906 
6907     ToCompute.reset(is_Computed);
6908     extract_data_dual(Dual, ToCompute);
6909 }
6910 
6911 //---------------------------------------------------------------------------
6912 
6913 template <typename Integer>
compute_rational_data(ConeProperties & ToCompute)6914 void Cone<Integer>::compute_rational_data(ConeProperties& ToCompute) {
6915 
6916     if(inhomogeneous || using_renf<Integer>())
6917         return;
6918     if(!ToCompute.test(ConeProperty::Multiplicity)) // This routine aims at the computation
6919         return;                                     // of multiplicities by better exploutation
6920     if(!isComputed(ConeProperty::OriginalMonoidGenerators))       // of unimodularity.
6921         return;
6922     if(internal_index == 1)         // This is the critical point: the external index
6923         return;                                     // divides all determinants computed.
6924                                                     // So no unimodularity if it is > 1.
6925 
6926     if(!isComputed(ConeProperty::Grading)) // The coordinate change below
6927         return;                           // coud produce an implicit grading
6928                                           // that is not liftable
6929 
6930     if(BasisMaxSubspace.nr_of_rows() > 0)
6931         return;
6932 
6933     // We have generators and they span a proper sublattice
6934     // of the lattice in which we must compute.
6935 
6936     size_t nr_goals = ToCompute.goals().count();
6937     size_t nr_vol_goals = 1;     //  We have Multiplicity already
6938     if(ToCompute.test(ConeProperty::Volume))
6939         nr_vol_goals++;
6940     if(ToCompute.test(ConeProperty::SupportHyperplanes)) // they can be computed alongside
6941         nr_vol_goals++;
6942    if(ToCompute.test(ConeProperty::ExtremeRays))        // ditto
6943         nr_vol_goals++;
6944     if(nr_goals != nr_vol_goals)    // There is something else asked for that does not allow the
6945         return;                     // reduction of the lattice
6946 
6947     // So we want to compute only things for which we can pass to
6948     // a sublattice.
6949 
6950     if(verbose)
6951         verboseOutput() << "Computing copy of cone with lattice spanned by generators" << endl;
6952 
6953     Matrix<Integer> GradMat(Grading);
6954     Cone<Integer> D(Type::cone_and_lattice, Generators, Type::grading, GradMat, Type::inequalities, SupportHyperplanes);
6955     if(!isComputed(ConeProperty::SupportHyperplanes) && ToCompute.test(ConeProperty::SupportHyperplanes))
6956         D.compute(ConeProperty::Multiplicity, ConeProperty::SupportHyperplanes);
6957     else
6958         D.compute(ConeProperty::Multiplicity);
6959 
6960     if(D.isComputed(ConeProperty::SupportHyperplanes) && !isComputed(ConeProperty::SupportHyperplanes)){
6961         swap(SupportHyperplanes, D.SupportHyperplanes);
6962         setComputed(ConeProperty::SupportHyperplanes);
6963     }
6964     if(D.isComputed(ConeProperty::ExtremeRays) && !isComputed(ConeProperty::ExtremeRays)){
6965         Generators = D.Generators; // to take reordering into account
6966         swap(D.ExtremeRays, ExtremeRays);
6967         ExtremeRaysRecCone = ExtremeRays;
6968         ExtremeRaysIndicator = D.ExtremeRaysIndicator;
6969         setComputed(ConeProperty::ExtremeRays);
6970     }
6971     if(!D.isComputed(ConeProperty::Multiplicity))
6972       return;
6973     mpq_class raw_mult;
6974     raw_mult = D.multiplicity;
6975     // cout << "MMM " << raw_mult << " " << raw_mult *convertTo<mpz_class>(internal_index) << endl;
6976     raw_mult *= convertTo<mpz_class>(internal_index);
6977 
6978     mpz_class large_grading_denom = convertTo<mpz_class>(D.GradingDenom); // grading denom on small lattice --> large denom
6979     // cout << "Large " << large_grading_denom << endl;
6980     vector<Integer> test_grading = BasisChangePointed.to_sublattice_dual_no_div(Grading);
6981     mpz_class small_grading_denom = convertTo<mpz_class>(v_gcd(test_grading)); // the grading denom of the given grading
6982     if(ToCompute.test(ConeProperty::NoGradingDenom)) // we make the official GradingDenom
6983         GradingDenom = 1;
6984     else
6985         GradingDenom = convertTo<Integer>(small_grading_denom);
6986     setComputed(ConeProperty::GradingDenom);
6987     // cout << "Small " << small_grading_denom << endl;
6988     for(size_t i=0; i < D.getRank(); ++i)
6989         raw_mult /= large_grading_denom;
6990     raw_mult *= small_grading_denom; // the usual correction, see comment in full_cone.cpp
6991     // At this point we have computed the multiplicity for the given grading
6992     if(!ToCompute.test(ConeProperty::NoGradingDenom)){
6993         for(size_t i=1; i< D.getRank(); ++i) // now we must take care of the official grading denomionator
6994             raw_mult *= small_grading_denom;         // it comes in with the exponent = polytope dimension
6995     }
6996     multiplicity = raw_mult;
6997     setComputed(ConeProperty::Multiplicity); // see comment in full_cone.cpp
6998     if(verbose)
6999         verboseOutput() << "Returning to original cone" << endl;
7000 }
7001 
7002 template <>
compute_rational_data(ConeProperties & ToCompute)7003 void Cone<renf_elem_class>::compute_rational_data(ConeProperties& ToCompute) {
7004 
7005     return;
7006 }
7007 
7008 //---------------------------------------------------------------------------
7009 
7010 template <typename Integer>
try_multiplicity_by_descent(ConeProperties & ToCompute)7011 void Cone<Integer>::try_multiplicity_by_descent(ConeProperties& ToCompute) {
7012 
7013     if(inhomogeneous) // in this case multiplicity defined algebraically, not as the volume of a polytope
7014         return;
7015 
7016     if(using_renf<Integer>()) // descent not usable for renf
7017         return;
7018 
7019    if(isComputed(ConeProperty::Multiplicity) || !ToCompute.test(ConeProperty::Multiplicity)) //nothing to do here
7020         return;
7021 
7022     if (ToCompute.test(ConeProperty::NoDescent) || ToCompute.test(ConeProperty::SignedDec)
7023                                     || ToCompute.test(ConeProperty::Symmetrize)) // user wants something different
7024         return;
7025 
7026     if (ToCompute.test(ConeProperty::HilbertSeries) || ToCompute.test(ConeProperty::WeightedEhrhartSeries) ||
7027         ToCompute.test(ConeProperty::VirtualMultiplicity) || ToCompute.test(ConeProperty::Integral) ||
7028         ToCompute.test(ConeProperty::Triangulation) || ToCompute.test(ConeProperty::StanleyDec) ||
7029         ToCompute.test(ConeProperty::TriangulationDetSum) || ToCompute.test(ConeProperty::TriangulationSize) ||
7030         ToCompute.test(ConeProperty::Symmetrize)) // needs triangulation
7031         return;
7032 
7033     if (!ToCompute.test(ConeProperty::Descent)) {  // we use Descent by default if there are not too many facets
7034         if ((Generators.nr_of_rows() >0 && SupportHyperplanes.nr_of_rows() > 3 * Generators.nr_of_rows() ) ||
7035             SupportHyperplanes.nr_of_rows() <= BasisChangePointed.getRank()) // if we start from generators, descent is not used by default
7036             return;
7037     }
7038 
7039     if(ToCompute.test(ConeProperty::NoGradingDenom))
7040         compute(ConeProperty::ExtremeRays, ConeProperty::Grading, ConeProperty::NoGradingDenom);
7041     else
7042         compute(ConeProperty::ExtremeRays, ConeProperty::Grading);
7043 
7044     if(isComputed(ConeProperty::Multiplicity)) // can happen !!
7045         return;
7046 
7047     try_multiplicity_of_para(ToCompute);  // we try this first, even if Descent is set
7048     if (isComputed(ConeProperty::Multiplicity))
7049         return;
7050 
7051     if(BasisChangePointed.getRank() == 0){ // we want to go through full_cone
7052         return;
7053     }
7054 
7055     if (verbose)
7056         verboseOutput() << "Multiplicity by descent in the face lattice" << endl;
7057 
7058     if (change_integer_type) {
7059         try {
7060             Matrix<MachineInteger> ExtremeRaysMI, SupportHyperplanesMI;
7061             vector<MachineInteger> GradingMI;
7062             BasisChangePointed.convert_to_sublattice(ExtremeRaysMI, ExtremeRays);
7063             BasisChangePointed.convert_to_sublattice_dual(SupportHyperplanesMI, SupportHyperplanes);
7064             if (ToCompute.test(ConeProperty::NoGradingDenom))
7065                 BasisChangePointed.convert_to_sublattice_dual_no_div(GradingMI, Grading);
7066             else
7067                 BasisChangePointed.convert_to_sublattice_dual(GradingMI, Grading);
7068             DescentSystem<MachineInteger> FF(ExtremeRaysMI, SupportHyperplanesMI, GradingMI);
7069             FF.set_verbose(verbose);
7070             FF.setExploitAutoms(ToCompute.test(ConeProperty::ExploitIsosMult));
7071             FF.compute();
7072             multiplicity = FF.getMultiplicity();
7073         } catch (const ArithmeticException& e) {
7074             if (verbose) {
7075                 verboseOutput() << e.what() << endl;
7076                 verboseOutput() << "Restarting with a bigger type." << endl;
7077             }
7078             change_integer_type = false;
7079         }
7080     }
7081 
7082     if (!change_integer_type) {
7083         DescentSystem<Integer> FF;
7084         if (BasisChangePointed.IsIdentity()) {
7085             vector<Integer> GradingEmb;
7086             if (ToCompute.test(ConeProperty::NoGradingDenom))
7087                 GradingEmb = BasisChangePointed.to_sublattice_dual_no_div(Grading);
7088             else
7089                 GradingEmb = BasisChangePointed.to_sublattice_dual(Grading);
7090             FF = DescentSystem<Integer>(ExtremeRays, SupportHyperplanes, GradingEmb, false); // no swapping
7091         }
7092         else {
7093             Matrix<Integer> ExtremeRaysEmb, SupportHyperplanesEmb;
7094             vector<Integer> GradingEmb;
7095             ExtremeRaysEmb = BasisChangePointed.to_sublattice(ExtremeRays);
7096             SupportHyperplanesEmb = BasisChangePointed.to_sublattice_dual(SupportHyperplanes);
7097             if (ToCompute.test(ConeProperty::NoGradingDenom))
7098                 GradingEmb = BasisChangePointed.to_sublattice_dual_no_div(Grading);
7099             else
7100                 GradingEmb = BasisChangePointed.to_sublattice_dual(Grading);
7101             FF = DescentSystem<Integer>(ExtremeRaysEmb, SupportHyperplanesEmb, GradingEmb);
7102         }
7103         FF.set_verbose(verbose);
7104         FF.setExploitAutoms(ToCompute.test(ConeProperty::ExploitIsosMult));
7105         FF.compute();
7106         multiplicity = FF.getMultiplicity();
7107     }
7108 
7109     // now me must correct the multiplicity if NoGradingDenom is set,
7110     // namely multiply it by the GradingDenom
7111     // as in full_cone.cpp (see comment there)
7112     if (ToCompute.test(ConeProperty::NoGradingDenom)) {
7113         vector<Integer> test_grading = BasisChangePointed.to_sublattice_dual_no_div(Grading);
7114         Integer corr_factor = v_gcd(test_grading);
7115         multiplicity *= convertTo<mpz_class>(corr_factor);
7116     }
7117 
7118     setComputed(ConeProperty::Multiplicity);
7119     setComputed(ConeProperty::Descent);
7120     if (verbose)
7121         verboseOutput() << "Multiplicity by descent done" << endl;
7122 }
7123 
7124 //---------------------------------------------------------------------------
7125 
7126 template <typename Integer>
try_multiplicity_of_para(ConeProperties & ToCompute)7127 void Cone<Integer>::try_multiplicity_of_para(ConeProperties& ToCompute) {
7128 
7129     if (( using_renf<Integer>() || (!inhomogeneous && !ToCompute.test(ConeProperty::Multiplicity)) ||
7130          (inhomogeneous && !ToCompute.test(ConeProperty::Volume))) ||
7131         !check_parallelotope())
7132         return;
7133 
7134     SupportHyperplanes.remove_row(Dehomogenization);
7135     setComputed(ConeProperty::SupportHyperplanes);
7136     addition_constraints_allowed=true;
7137     setComputed(ConeProperty::MaximalSubspace);
7138     setComputed(ConeProperty::Sublattice);
7139     pointed = true;
7140     setComputed(ConeProperty::IsPointed);
7141     if(inhomogeneous){
7142         affine_dim=dim-1;
7143         setComputed(ConeProperty::AffineDim);
7144         recession_rank = 0;
7145         setComputed(ConeProperty::RecessionRank);
7146     }
7147 
7148     if (verbose)
7149         verboseOutput() << "Multiplicity/Volume of parallelotope ...";
7150 
7151     vector<Integer> Grad;
7152 
7153     if (inhomogeneous) {
7154         Grad = Dehomogenization;
7155     }
7156     else {
7157         Grad = Grading;
7158     }
7159 
7160     size_t polytope_dim = dim - 1;
7161 
7162     // find a corner
7163     // CornerKey lists the supphyps that meet in the corner
7164     // OppositeKey lists the respective parallels
7165     vector<key_t> CornerKey, OppositeKey;
7166     for (size_t pc = 0; pc < polytope_dim; ++pc) {
7167         for (size_t i = 0; i < 2 * polytope_dim; ++i) {
7168             if (Pair[i][pc] == true) {
7169                 if (ParaInPair[i][pc] == false)
7170                     CornerKey.push_back(i);
7171                 else
7172                     OppositeKey.push_back(i);
7173             }
7174         }
7175     }
7176 
7177     Matrix<Integer> Simplex(0, dim);
7178     vector<Integer> gen;
7179     gen = SupportHyperplanes.submatrix(CornerKey).kernel(false)[0];
7180     if (v_scalar_product(gen, Grad) < 0)
7181         v_scalar_multiplication<Integer>(gen, -1);
7182     Simplex.append(gen);
7183     for (size_t i = 0; i < polytope_dim; ++i) {
7184         vector<key_t> ThisKey = CornerKey;
7185         ThisKey[i] = OppositeKey[i];
7186         gen = SupportHyperplanes.submatrix(ThisKey).kernel(false)[0];
7187         if (v_scalar_product(gen, Grad) < 0)
7188             v_scalar_multiplication<Integer>(gen, -1);
7189         Simplex.append(gen);
7190     }
7191 
7192     if (Simplex.nr_of_rows() <= 1)
7193         return;
7194 
7195     Cone<Integer> VolCone(Type::cone, Simplex, Type::grading, Matrix<Integer>(Grad));
7196     VolCone.setVerbose(false);
7197     if (inhomogeneous || ToCompute.test(ConeProperty::NoGradingDenom))
7198         VolCone.compute(ConeProperty::Multiplicity, ConeProperty::NoGradingDenom);
7199     else
7200         VolCone.compute(ConeProperty::Multiplicity);
7201     mpq_class mult_or_vol = VolCone.getMultiplicity();
7202     mult_or_vol *= nmz_factorial((long)polytope_dim);
7203     if (!inhomogeneous) {
7204         multiplicity = mult_or_vol;
7205         setComputed(ConeProperty::Multiplicity);
7206         if (ToCompute.test(ConeProperty::Volume))
7207             volume = mult_or_vol;
7208     }
7209     else {
7210         volume = mult_or_vol;
7211     }
7212 
7213     if (ToCompute.test(ConeProperty::Volume)) {
7214         euclidean_volume = mpq_to_nmz_float(volume) * euclidean_corr_factor();
7215         setComputed(ConeProperty::Volume);
7216         setComputed(ConeProperty::EuclideanVolume);
7217     }
7218 
7219     if (verbose)
7220         verboseOutput() << "done" << endl;
7221 }
7222 
7223 //---------------------------------------------------------------------------
7224 
7225 template <typename Integer>
treat_polytope_as_being_hom_defined(ConeProperties ToCompute)7226 void Cone<Integer>::treat_polytope_as_being_hom_defined(ConeProperties ToCompute) {
7227 
7228     if(!inhomogeneous)
7229         return;
7230 
7231     if (using_renf<Integer>())
7232         return;
7233 
7234     if (ToCompute.intersection_with(treated_as_hom_props()).none())
7235         return;  // homogeneous treatment not necessary
7236 
7237     ConeProperties ToComputeFirst;
7238     ToComputeFirst.set(ConeProperty::Generators);
7239     ToComputeFirst.set(ConeProperty::SupportHyperplanes);
7240     ToComputeFirst.set(ConeProperty::ExtremeRays);
7241     compute(ToComputeFirst);
7242     ToCompute.reset(is_Computed);
7243 
7244     bool empty_polytope = true;
7245     for (size_t i = 0; i < Generators.nr_of_rows(); ++i){
7246         Integer test = v_scalar_product(Dehomogenization, Generators[i]);
7247         if (test <= 0)
7248             throw NotComputableException("At least one goal not computable for unbounded polyhedra.");
7249         if(test > 0)
7250             empty_polytope = false;
7251     }
7252 
7253     if (empty_polytope && Generators.nr_of_rows() > 0) {
7254         throw NotComputableException(
7255             "At least obe goal  not computable for empty polytope with non-subspace recession cone.");
7256     }
7257 
7258     if(empty_polytope){
7259         affine_dim = -1;
7260         setComputed(ConeProperty::AffineDim);
7261         volume = 0;
7262         euclidean_volume = 0;
7263         setComputed(ConeProperty::Volume);
7264         setComputed(ConeProperty::EuclideanVolume);
7265         ToCompute.reset(is_Computed);
7266     }
7267 
7268     Cone Hom(*this); // make a copy and make it homogeneous
7269     Hom.Grading = Dehomogenization;
7270     Hom.setComputed(ConeProperty::Grading);
7271     Hom.Dehomogenization.resize(0);
7272     Hom.inhomogeneous = false;
7273     ConeProperties HomToCompute = ToCompute;
7274     HomToCompute.reset(ConeProperty::FaceLattice); // better to do this in the
7275     HomToCompute.reset(ConeProperty::FVector);     // original inhomogeneous settimg
7276     HomToCompute.reset(ConeProperty::Incidence);   //
7277 
7278     HomToCompute.reset(ConeProperty::VerticesOfPolyhedron);  //
7279     HomToCompute.reset(ConeProperty::ModuleRank);            //
7280     HomToCompute.reset(ConeProperty::RecessionRank);         //  these 6 will be computed below
7281     HomToCompute.reset(ConeProperty::AffineDim);             //             //
7282     HomToCompute.reset(ConeProperty::VerticesOfPolyhedron);  //
7283     HomToCompute.reset(ConeProperty::ModuleGenerators);  //
7284     HomToCompute.reset(ConeProperty::ModuleGeneratorsOverOriginalMonoid); //
7285     HomToCompute.reset(ConeProperty::HilbertBasis); // we definitely don't want this
7286 
7287     if (ToCompute.test(ConeProperty::HilbertBasis) || ToCompute.test(ConeProperty::ModuleRank)
7288                     || ToCompute.test(ConeProperty::ModuleGeneratorsOverOriginalMonoid)  )
7289         HomToCompute.set(ConeProperty::LatticePoints);      // ==> NoGradingDenom
7290 
7291     Hom.compute(HomToCompute);  // <--------------------------- Here we compute
7292 
7293     /* compute(ConeProperty::Sublattice);
7294     if (!isComputed(ConeProperty::Sublattice))
7295         throw FatalException("Could not compute sublattice");
7296 
7297     pass_to_pointed_quotient();*/
7298 
7299     if (Hom.isComputed(ConeProperty::Deg1Elements)) {
7300         swap(ModuleGenerators, Hom.Deg1Elements);
7301         setComputed(ConeProperty::HilbertBasis);
7302         setComputed(ConeProperty::ModuleGenerators);
7303         module_rank = ModuleGenerators.nr_of_rows();
7304         setComputed(ConeProperty::ModuleRank);
7305         number_lattice_points = module_rank;
7306         setComputed(ConeProperty::NumberLatticePoints);
7307 
7308         if (ToCompute.test(ConeProperty::ModuleGeneratorsOverOriginalMonoid) ) {
7309             ModuleGeneratorsOverOriginalMonoid = ModuleGenerators;
7310             setComputed(ConeProperty::ModuleGeneratorsOverOriginalMonoid);
7311         }
7312     }
7313 
7314     if(Hom.isComputed(ConeProperty::NumberLatticePoints)){ // sometimes computed from the Hilbert series
7315         number_lattice_points = Hom.number_lattice_points;
7316         setComputed(ConeProperty::NumberLatticePoints);
7317 
7318     }
7319 
7320     IntData = Hom.IntData;
7321     if(Hom.isComputed(ConeProperty::WeightedEhrhartSeries))
7322         setComputed(ConeProperty::WeightedEhrhartSeries);
7323     if(Hom.isComputed(ConeProperty::WeightedEhrhartQuasiPolynomial))
7324         setComputed(ConeProperty::WeightedEhrhartQuasiPolynomial);
7325     if(Hom.isComputed(ConeProperty::Integral))
7326         setComputed(ConeProperty::Integral);
7327     if(Hom.isComputed(ConeProperty::EuclideanIntegral))
7328         setComputed(ConeProperty::EuclideanIntegral);
7329     if(Hom.isComputed(ConeProperty::VirtualMultiplicity))
7330         setComputed(ConeProperty::VirtualMultiplicity);
7331 
7332     if (Hom.isComputed(ConeProperty::HilbertSeries)) {
7333         setComputed(ConeProperty::EhrhartSeries);
7334         swap(EhrSeries, Hom.HSeries);
7335     }
7336 
7337     if(Hom.isComputed(ConeProperty::HSOP))
7338         setComputed(ConeProperty::HSOP);
7339 
7340     if(Hom.isComputed(ConeProperty::Volume)){
7341         volume = Hom.volume;
7342         setComputed(ConeProperty::Volume);
7343     }
7344     if(Hom.isComputed(ConeProperty::EuclideanVolume)){
7345         euclidean_volume = Hom.euclidean_volume;
7346         setComputed(ConeProperty::EuclideanVolume);
7347     }
7348 
7349     if(!isComputed(ConeProperty::BasicTriangulation) && Hom.isComputed(ConeProperty::BasicTriangulation)){
7350         swap(BasicTriangulation, Hom.BasicTriangulation);
7351         setComputed(ConeProperty::BasicTriangulation);
7352     }
7353 
7354     bool triang_computed = false;
7355     if(Hom.isComputed(ConeProperty::Triangulation)){
7356         setComputed(ConeProperty::Triangulation);
7357         triang_computed = true;
7358     }
7359     if(Hom.isComputed(ConeProperty::PlacingTriangulation)){
7360         setComputed(ConeProperty::Triangulation);
7361         triang_computed = true;
7362     }
7363     if(Hom.isComputed(ConeProperty::PullingTriangulation)){
7364         setComputed(ConeProperty::Triangulation);
7365         triang_computed = true;
7366     }
7367     if(Hom.isComputed(ConeProperty::UnimodularTriangulation)){
7368         setComputed(ConeProperty::UnimodularTriangulation);
7369         triang_computed = true;
7370     }
7371     if(Hom.isComputed(ConeProperty::LatticePointTriangulation)){
7372         setComputed(ConeProperty::LatticePointTriangulation);
7373         triang_computed = true;
7374     }
7375     if(Hom.isComputed(ConeProperty::AllGeneratorsTriangulation)){
7376         setComputed(ConeProperty::AllGeneratorsTriangulation);
7377         triang_computed = true;
7378     }
7379     if(triang_computed)
7380         swap(Triangulation, Hom.Triangulation);
7381 
7382     if(Hom.isComputed(ConeProperty::TriangulationSize)) {
7383         TriangulationSize = Hom.TriangulationSize;
7384         setComputed(ConeProperty::TriangulationSize);
7385     }
7386     if(Hom.isComputed(ConeProperty::TriangulationDetSum)) {
7387         TriangulationDetSum= Hom.TriangulationDetSum;
7388         setComputed(ConeProperty::TriangulationDetSum);
7389     }
7390 
7391     if(Hom.isComputed(ConeProperty::BasicTriangulation) || Hom.isComputed(ConeProperty::TriangulationSize)
7392             || Hom.isComputed(ConeProperty::TriangulationDetSum) ){
7393         triangulation_is_nested = Hom.triangulation_is_nested;
7394         triangulation_is_partial = Hom.triangulation_is_partial;
7395         setComputed(ConeProperty::IsTriangulationPartial);
7396         setComputed(ConeProperty::IsTriangulationNested);
7397     }
7398 
7399     if(Hom.isComputed(ConeProperty::ConeDecomposition)){
7400         setComputed(ConeProperty::ConeDecomposition);
7401     }
7402 
7403     if(Hom.isComputed(ConeProperty::StanleyDec)){
7404         swap(StanleyDec,Hom.StanleyDec);
7405         setComputed(ConeProperty::StanleyDec);
7406     }
7407 
7408     if(Hom.isComputed(ConeProperty::ExcludedFaces)){
7409         swap(ExcludedFaces,Hom.ExcludedFaces);
7410         setComputed(ConeProperty::ExcludedFaces);
7411     }
7412 
7413     if(Hom.isComputed(ConeProperty::CoveringFace)){
7414         swap(CoveringFace,Hom.CoveringFace);
7415         setComputed(ConeProperty::CoveringFace);
7416     }
7417 
7418     if(Hom.isComputed(ConeProperty::IsEmptySemiOpen)){
7419         empty_semiopen = Hom.empty_semiopen;
7420         setComputed(ConeProperty::IsEmptySemiOpen);
7421     }
7422 
7423     bool automs_computed = false;
7424     if(Hom.isComputed(ConeProperty::Automorphisms)){
7425         setComputed(ConeProperty::Automorphisms);
7426         automs_computed = true;
7427     }
7428     if(Hom.isComputed(ConeProperty::RationalAutomorphisms)){
7429         setComputed(ConeProperty::RationalAutomorphisms);
7430         automs_computed = true;
7431     }
7432     if(Hom.isComputed(ConeProperty::EuclideanAutomorphisms)){
7433         setComputed(ConeProperty::EuclideanAutomorphisms);
7434         automs_computed = true;
7435     }
7436     if(Hom.isComputed(ConeProperty::CombinatorialAutomorphisms)){
7437         setComputed(ConeProperty::CombinatorialAutomorphisms);
7438         automs_computed = true;
7439     }
7440     if(automs_computed){
7441         Automs = Hom.Automs;
7442         Automs.VerticesPerms = Automs.ExtRaysPerms; //make things inhomogeneous
7443         Automs.VerticesOrbits = Automs.ExtRaysOrbits;
7444         Automs.ExtRaysPerms.clear();
7445         Automs.ExtRaysOrbits.clear();
7446     }
7447     if(Hom.isComputed(ConeProperty::DualIncidence)){
7448         swap(Hom.DualSuppHypInd, DualSuppHypInd);
7449         setComputed(ConeProperty::DualIncidence);
7450     }
7451     if(Hom.isComputed(ConeProperty::DualFaceLattice)){
7452         swap(Hom.DualFaceLat, DualFaceLat);
7453         setComputed(ConeProperty::DualFaceLattice);
7454     }
7455     if(Hom.isComputed(ConeProperty::DualFVector)){
7456         dual_f_vector = Hom.dual_f_vector;
7457         setComputed(ConeProperty::DualFVector);
7458     }
7459     if(Hom.isComputed(ConeProperty::FixedPrecision))
7460         setComputed(ConeProperty::FixedPrecision);
7461 
7462     recession_rank = Hom.BasisMaxSubspace.nr_of_rows(); // in our polytope case
7463     setComputed(ConeProperty::RecessionRank);
7464     if(!empty_polytope){
7465         affine_dim = getRank() - 1;
7466         setComputed(ConeProperty::AffineDim);
7467     }
7468 }
7469 
7470 //---------------------------------------------------------------------------
7471 
7472 template <typename Integer>
try_Hilbert_Series_from_lattice_points(const ConeProperties & ToCompute)7473 void Cone<Integer>::try_Hilbert_Series_from_lattice_points(const ConeProperties& ToCompute) {
7474     if (!inhomogeneous || !isComputed(ConeProperty::ModuleGenerators) ||
7475         !(isComputed(ConeProperty::RecessionRank) && recession_rank == 0) || !isComputed(ConeProperty::Grading))
7476         return;
7477 
7478     multiplicity = static_cast<unsigned long>(ModuleGenerators.nr_of_rows());
7479     setComputed(ConeProperty::Multiplicity);
7480 
7481     if (!ToCompute.test(ConeProperty::HilbertSeries))
7482         return;
7483 
7484     if (verbose)
7485         verboseOutput() << "Computing Hilbert series from lattice points" << endl;
7486 
7487     vector<num_t> h_vec_pos(1), h_vec_neg;
7488 
7489     for (size_t i = 0; i < ModuleGenerators.nr_of_rows(); ++i) {
7490         long deg = convertToLong(v_scalar_product(Grading, ModuleGenerators[i]));
7491         if (deg >= 0) {
7492             if (deg >= (long)h_vec_pos.size())
7493                 h_vec_pos.resize(deg + 1);
7494             h_vec_pos[deg]++;
7495         }
7496         else {
7497             deg *= -1;
7498             if (deg >= (long)h_vec_neg.size())
7499                 h_vec_neg.resize(deg + 1);
7500             h_vec_neg[deg]++;
7501         }
7502     }
7503 
7504     /*cout << "Pos " << h_vec_pos;
7505     cout << "Neg " << h_vec_neg;*/
7506 
7507     make_Hilbert_series_from_pos_and_neg(h_vec_pos, h_vec_neg);
7508 }
7509 
7510 template <>
try_Hilbert_Series_from_lattice_points(const ConeProperties & ToCompute)7511 void Cone<renf_elem_class>::try_Hilbert_Series_from_lattice_points(const ConeProperties& ToCompute) {
7512     assert(false);
7513 }
7514 
7515 //---------------------------------------------------------------------------
7516 
7517 template <typename Integer>
make_Hilbert_series_from_pos_and_neg(const vector<num_t> & h_vec_pos,const vector<num_t> & h_vec_neg)7518 void Cone<Integer>::make_Hilbert_series_from_pos_and_neg(const vector<num_t>& h_vec_pos, const vector<num_t>& h_vec_neg) {
7519     vector<num_t> hv = h_vec_pos;
7520     long raw_shift = 0;
7521     if (h_vec_neg.size() > 0) {  // insert negative degrees
7522         raw_shift = -(h_vec_neg.size() - 1);
7523         for (size_t j = 1; j < h_vec_neg.size(); ++j)
7524             hv.insert(hv.begin(), h_vec_neg[j]);
7525     }
7526 
7527     HSeries.add(hv, vector<denom_t>());
7528     HSeries.setShift(raw_shift);
7529     HSeries.adjustShift();
7530     HSeries.simplify();
7531     setComputed(ConeProperty::HilbertSeries);
7532     // setComputed(ConeProperty::ExplicitHilbertSeries);
7533 }
7534 
7535 //---------------------------------------------------------------------------
7536 
7537 template <typename Integer>
make_face_lattice(const ConeProperties & ToCompute)7538 void Cone<Integer>::make_face_lattice(const ConeProperties& ToCompute) {
7539 
7540     bool something_to_do_primal = (ToCompute.test(ConeProperty::FaceLattice) && !isComputed(ConeProperty::FaceLattice)) ||
7541                            (ToCompute.test(ConeProperty::FVector) && !isComputed(ConeProperty::FVector)) ||
7542                            (ToCompute.test(ConeProperty::Incidence) && !isComputed(ConeProperty::Incidence));
7543 
7544     bool something_to_do_dual = (ToCompute.test(ConeProperty::DualFaceLattice) && !isComputed(ConeProperty::DualFaceLattice)) ||
7545                            (ToCompute.test(ConeProperty::DualFVector) && !isComputed(ConeProperty::DualFVector)) ||
7546                            (ToCompute.test(ConeProperty::DualIncidence) && !isComputed(ConeProperty::DualIncidence));
7547 
7548     if(!something_to_do_dual && !something_to_do_primal)
7549         return;
7550 
7551     if(something_to_do_dual && something_to_do_primal)
7552         throw BadInputException("Only one of primal or dual face lattice/f-vector/incidence allowed");
7553 
7554     if(something_to_do_dual && inhomogeneous)
7555         throw BadInputException("Dual face lattice/f-vector/incidence not computable for inhomogeneous input");
7556 
7557     compute(ConeProperty::ExtremeRays, ConeProperty::SupportHyperplanes); // both necessary
7558                                          // since ExtremeRays can be comuted without SupportHyperplanes
7559                                          // if the cone is not full dimensional
7560 
7561     bool only_f_vector = (something_to_do_primal && !ToCompute.test(ConeProperty::FaceLattice) &&
7562                                                     !ToCompute.test(ConeProperty::Incidence))
7563                       || (something_to_do_dual && !ToCompute.test(ConeProperty::DualFaceLattice) &&
7564                                                     !ToCompute.test(ConeProperty::DualIncidence));
7565 
7566     bool dualize = only_f_vector &&  ((something_to_do_primal && ExtremeRays.nr_of_rows() < SupportHyperplanes.nr_of_rows())
7567                                  ||  (something_to_do_dual && ExtremeRays.nr_of_rows() > SupportHyperplanes.nr_of_rows()) )
7568                   && face_codim_bound < 0;
7569 
7570 
7571     if( (something_to_do_primal && !dualize) || (something_to_do_dual && dualize) || inhomogeneous ){
7572         make_face_lattice_primal(ToCompute);
7573     }
7574     else{
7575         make_face_lattice_dual(ToCompute);
7576     }
7577 
7578 }
7579 //---------------------------------------------------------------------------
7580 
7581 template <typename Integer>
make_face_lattice_primal(const ConeProperties & ToCompute)7582 void Cone<Integer>::make_face_lattice_primal(const ConeProperties& ToCompute) {
7583 
7584     if(verbose && ToCompute.test(ConeProperty::DualFVector))
7585         verboseOutput() << "Going to the primal side for the dual f-vector" << endl;
7586     if (verbose)
7587         verboseOutput() << "Computing incidence/face lattice/f-vector ... " << endl;
7588 
7589     Matrix<Integer> SuppHypPointed;
7590     BasisChangePointed.convert_to_sublattice_dual(SuppHypPointed,SupportHyperplanes);
7591     Matrix<Integer> VertOfPolPointed;
7592     BasisChangePointed.convert_to_sublattice(VertOfPolPointed,VerticesOfPolyhedron);
7593     Matrix<Integer> ExtrRCPointed;
7594     BasisChangePointed.convert_to_sublattice(ExtrRCPointed,ExtremeRaysRecCone);
7595     FaceLattice<Integer> FL(SuppHypPointed,VertOfPolPointed,ExtrRCPointed,inhomogeneous);
7596 
7597     if(ToCompute.test(ConeProperty::FaceLattice) || ToCompute.test(ConeProperty::FVector)
7598                                                  || ToCompute.test(ConeProperty::DualFVector))
7599         FL.compute(face_codim_bound,verbose,change_integer_type);
7600 
7601     if(ToCompute.test(ConeProperty::Incidence)){
7602         FL.get(SuppHypInd);
7603         setComputed(ConeProperty::Incidence);
7604     }
7605     if(ToCompute.test(ConeProperty::FaceLattice) ){
7606         FL.get(FaceLat);
7607         setComputed(ConeProperty::FaceLattice);
7608     }
7609     if(ToCompute.test(ConeProperty::FaceLattice) || ToCompute.test(ConeProperty::FVector)
7610                                                  || ToCompute.test(ConeProperty::DualFVector)){
7611         vector<size_t> prel_f_vector = FL.getFVector();
7612         if(!ToCompute.test(ConeProperty::DualFVector)){
7613             f_vector = prel_f_vector;
7614             setComputed(ConeProperty::FVector);
7615         }
7616         else{
7617             dual_f_vector.resize(prel_f_vector.size());
7618             for(size_t i = 0; i< prel_f_vector.size(); ++i)
7619                 dual_f_vector[i] = prel_f_vector[prel_f_vector.size()-1-i];
7620             setComputed(ConeProperty::DualFVector);
7621         }
7622     }
7623 }
7624 
7625 //---------------------------------------------------------------------------
7626 
7627 template <typename Integer>
make_face_lattice_dual(const ConeProperties & ToCompute)7628 void Cone<Integer>::make_face_lattice_dual(const ConeProperties& ToCompute) {
7629 
7630    if(verbose && ToCompute.test(ConeProperty::FVector))
7631         verboseOutput() << "Going to the dual side for the primal f-vector" << endl;
7632     if (verbose)
7633         verboseOutput() << "Computing dual incidence/face lattice/f-vector ... " << endl;
7634 
7635     // Note for the coordinate transformation:
7636     // On the dual space we must use the dual coordinate transformation
7637     // Since the primal extreme rays are the support hyperplanes on the dual space
7638     // they must be transformed by the dual of the dual = primal
7639     // The support hyperplanes are extreme rays on the dual.
7640     // They are transformed by the primal of the dual = dual.
7641 
7642     Matrix<Integer> SuppHypPointed;
7643     BasisChangePointed.convert_to_sublattice(SuppHypPointed,ExtremeRays); // We dualize !!!!
7644     Matrix<Integer> VertOfPolPointed; // empty matrix in the dual case
7645     Matrix<Integer> ExtrRCPointed;
7646     BasisChangePointed.convert_to_sublattice_dual(ExtrRCPointed,SupportHyperplanes); // We dualize !!!!
7647 
7648     FaceLattice<Integer> FL(SuppHypPointed,VertOfPolPointed,ExtrRCPointed,inhomogeneous);
7649 
7650     if(ToCompute.test(ConeProperty::DualFaceLattice) || ToCompute.test(ConeProperty::DualFVector)
7651                                                      || ToCompute.test(ConeProperty::FVector))
7652         FL.compute(face_codim_bound,verbose,change_integer_type);
7653 
7654     if(ToCompute.test(ConeProperty::DualIncidence)){
7655         FL.get(DualSuppHypInd);
7656         setComputed(ConeProperty::DualIncidence);
7657     }
7658     if(ToCompute.test(ConeProperty::DualFaceLattice) ){
7659         FL.get(DualFaceLat);
7660         setComputed(ConeProperty::DualFaceLattice);
7661     }
7662     if(ToCompute.test(ConeProperty::DualFaceLattice) || ToCompute.test(ConeProperty::DualFVector)
7663                                                  || ToCompute.test(ConeProperty::FVector)){
7664         vector<size_t> prel_f_vector = FL.getFVector();
7665         if(!ToCompute.test(ConeProperty::FVector)){
7666             dual_f_vector = prel_f_vector;
7667             setComputed(ConeProperty::DualFVector);
7668         }
7669         else{
7670             dual_f_vector.resize(prel_f_vector.size());
7671             for(size_t i = 0; i< prel_f_vector.size(); ++i)
7672                 f_vector[i] = prel_f_vector[prel_f_vector.size()-1-i];
7673             setComputed(ConeProperty::FVector);
7674         }
7675     }
7676 }
7677 
7678 //---------------------------------------------------------------------------
7679 
7680 template <typename Integer>
compute_combinatorial_automorphisms(const ConeProperties & ToCompute)7681 void Cone<Integer>::compute_combinatorial_automorphisms(const ConeProperties& ToCompute) {
7682     if (!ToCompute.test(ConeProperty::CombinatorialAutomorphisms) || isComputed(ConeProperty::CombinatorialAutomorphisms))
7683         return;
7684 
7685     if (verbose)
7686         verboseOutput() << "Computing combinatorial automorphism group" << endl;
7687 
7688     compute(ConeProperty::SupportHyperplanes, ConeProperty::ExtremeRays);
7689 
7690     Matrix<Integer> SpecialLinFoprms(0, dim);
7691 
7692     if (inhomogeneous) {
7693         SpecialLinFoprms.append(Dehomogenization);
7694     }
7695 
7696     /* set<AutomParam::Goals> AutomToCompute;
7697     AutomToCompute.insert(AutomParam::OrbitsPrimal);
7698     AutomToCompute.insert(AutomParam::OrbitsDual);*/
7699 
7700     Automs = AutomorphismGroup<Integer>(ExtremeRays, SupportHyperplanes, SpecialLinFoprms);
7701 
7702     Automs.compute(AutomParam::combinatorial);
7703 
7704    if (verbose)
7705         verboseOutput() << Automs.getQualitiesString() << "automorphism group of order " << Automs.getOrder() << "  done" << endl;
7706 
7707     extract_automorphisms(Automs);
7708 
7709     setComputed(ConeProperty::CombinatorialAutomorphisms);
7710 }
7711 
7712 //---------------------------------------------------------------------------
7713 template <typename Integer>
compute_input_automorphisms(const ConeProperties & ToCompute)7714 void Cone<Integer>::compute_input_automorphisms(const ConeProperties& ToCompute) {
7715     if (!ToCompute.test(ConeProperty::InputAutomorphisms) || isComputed(ConeProperty::InputAutomorphisms))
7716         return;
7717 
7718     if(Generators.nr_of_rows() >0)
7719         compute_input_automorphisms_gen(ToCompute);
7720     if(Generators.nr_of_rows() == 0){
7721             compute_input_automorphisms_ineq(ToCompute);
7722     }
7723     setComputed(ConeProperty::InputAutomorphisms);
7724 
7725     if (verbose)
7726         verboseOutput() << Automs.getQualitiesString() << "automorphism group of order " << Automs.getOrder() << "  done" << endl;
7727 }
7728 //---------------------------------------------------------------------------
7729 template <typename Integer>
compute_input_automorphisms_gen(const ConeProperties & ToCompute)7730 void Cone<Integer>::compute_input_automorphisms_gen(const ConeProperties& ToCompute) {
7731 
7732     if(verbose)
7733         verboseOutput() << "Computing automorphisms from input generators" << endl;
7734 
7735     Matrix<Integer> GeneratorsHere = BasisChangePointed.to_sublattice(Generators);
7736     Matrix<Integer> SpecialLinForms(0,BasisChangePointed.getRank());
7737     if(Grading.size() == dim)
7738         SpecialLinForms.append(BasisChangePointed.to_sublattice_dual(Grading));
7739     if(Dehomogenization.size() == dim)
7740                 SpecialLinForms.append(BasisChangePointed.to_sublattice_dual_no_div(Dehomogenization));
7741 
7742     Matrix<Integer> Empty(0, BasisChangePointed.getRank());
7743     Automs = AutomorphismGroup<Integer>(GeneratorsHere, Empty, SpecialLinForms);
7744     Automs.compute(AutomParam::input_gen);
7745 
7746     Automs.setGensRef(Generators);
7747 }
7748 //---------------------------------------------------------------------------
7749 template <typename Integer>
compute_input_automorphisms_ineq(const ConeProperties & ToCompute)7750 void Cone<Integer>::compute_input_automorphisms_ineq(const ConeProperties& ToCompute) {
7751 
7752     if(verbose)
7753         verboseOutput() << "Computing automorphisms from input inequalities" << endl;
7754 
7755     Matrix<Integer> SpecialGens(0,BasisChangePointed.getRank());
7756     Matrix<Integer> Empty(0,BasisChangePointed.getRank());
7757     if(Grading.size() == dim)
7758         SpecialGens.append(BasisChangePointed.to_sublattice_dual(Grading));
7759     Matrix<Integer> InequalitiesHere = BasisChangePointed.to_sublattice_dual(SupportHyperplanes);
7760     if(inhomogeneous){
7761         SpecialGens.append(BasisChangePointed.to_sublattice_dual_no_div(Dehomogenization));
7762         InequalitiesHere.remove_row(BasisChangePointed.to_sublattice_dual(Dehomogenization));
7763     }
7764 
7765     Automs = AutomorphismGroup<Integer>(InequalitiesHere, SpecialGens, Empty, Empty);
7766     Automs.compute(AutomParam::input_ineq);
7767 
7768     InequalitiesHere = SupportHyperplanes;
7769     if(inhomogeneous){
7770         InequalitiesHere.remove_row(Dehomogenization);
7771     }
7772     Automs.setGensRef(InequalitiesHere);
7773 }
7774 
7775 //---------------------------------------------------------------------------
7776 template <typename Integer>
compute_ambient_automorphisms(const ConeProperties & ToCompute)7777 void Cone<Integer>::compute_ambient_automorphisms(const ConeProperties& ToCompute) {
7778     if (!ToCompute.test(ConeProperty::AmbientAutomorphisms) || isComputed(ConeProperty::AmbientAutomorphisms))
7779         return;
7780     if(Generators.nr_of_rows() >0)
7781         compute_ambient_automorphisms_gen(ToCompute);
7782     if(Generators.nr_of_rows() == 0 && SupportHyperplanes.nr_of_rows() > 0){
7783         if(BasisChange.IsIdentity())
7784             compute_ambient_automorphisms_ineq(ToCompute);
7785         else
7786             throw BadInputException("Ambient automorphisms not computable from input automorphisms");
7787     }
7788     setComputed(ConeProperty::AmbientAutomorphisms);
7789 
7790 
7791     if (verbose)
7792         verboseOutput() << Automs.getQualitiesString() << "automorphism group of order " << Automs.getOrder() << "  done" << endl;
7793 }
7794 //---------------------------------------------------------------------------
7795 template <typename Integer>
compute_ambient_automorphisms_gen(const ConeProperties & ToCompute)7796 void Cone<Integer>::compute_ambient_automorphisms_gen(const ConeProperties& ToCompute) {
7797 
7798     if(verbose)
7799         verboseOutput() << "Computing ambient automorphisms from input generators" << endl;
7800 
7801     Matrix<Integer> UnitMatrix(dim);
7802     Matrix<Integer> SpecialLinForms(0,dim);
7803     if(Grading.size() == dim)
7804         SpecialLinForms.append(Grading);
7805     if(Dehomogenization.size() == dim)
7806         SpecialLinForms.append(Dehomogenization);
7807 
7808     Automs = AutomorphismGroup<Integer>(Generators, UnitMatrix, SpecialLinForms);
7809     Automs.compute(AutomParam::ambient_gen);
7810 }
7811 //---------------------------------------------------------------------------
7812 template <typename Integer>
compute_ambient_automorphisms_ineq(const ConeProperties & ToCompute)7813 void Cone<Integer>::compute_ambient_automorphisms_ineq(const ConeProperties& ToCompute) {
7814 
7815     if(verbose)
7816         verboseOutput() << "Computing ambient automorphisms from input inequalities" << endl;
7817 
7818     Matrix<Integer> UnitMatrix(dim);
7819     Matrix<Integer> SpecialGens(0,dim);
7820     Matrix<Integer> Empty(0,dim);
7821     if(Grading.size() == dim)
7822         SpecialGens.append(Grading);
7823     Matrix<Integer> InequalitiesHere = SupportHyperplanes;
7824     if(inhomogeneous){
7825         SpecialGens.append(Dehomogenization);
7826         InequalitiesHere.remove_row(Dehomogenization);
7827     }
7828 
7829     Automs = AutomorphismGroup<Integer>(InequalitiesHere, SpecialGens, UnitMatrix, Empty);
7830     Automs.compute(AutomParam::ambient_ineq);
7831 }
7832 
7833 //---------------------------------------------------------------------------
7834 
7835 template <typename Integer>
compute_euclidean_automorphisms(const ConeProperties & ToCompute)7836 void Cone<Integer>::compute_euclidean_automorphisms(const ConeProperties& ToCompute) {
7837     if (!ToCompute.test(ConeProperty::EuclideanAutomorphisms) || isComputed(ConeProperty::EuclideanAutomorphisms))
7838         return;
7839 
7840     compute(ConeProperty::SupportHyperplanes, ConeProperty::ExtremeRays);
7841 
7842     if (getDimMaximalSubspace() > 0)
7843         throw NotComputableException("Euclidean automorphisms not computable if maximal subspace is nonzero");
7844     if (inhomogeneous && getRecessionRank() > 0)
7845         throw NotComputableException("Unbounded polyhedron. Euclidean automorphisms only computable for polytopes");
7846     if (!inhomogeneous && !isComputed(ConeProperty::Grading))
7847         throw NotComputableException("No Grading. Euclidean automorphisms only computable for polytopes");
7848 
7849     if (verbose)
7850         verboseOutput() << "Computing euclidean automorphism group" << endl;
7851 
7852     Matrix<Integer> SpecialLinFoprms(0, dim);
7853     if (!inhomogeneous) {
7854         SpecialLinFoprms.append(Grading);
7855     }
7856     if (inhomogeneous) {
7857         SpecialLinFoprms.append(Dehomogenization);
7858     }
7859 
7860     /* set<AutomParam::Goals> AutomToCompute;
7861     AutomToCompute.insert(AutomParam::OrbitsPrimal);
7862     AutomToCompute.insert(AutomParam::OrbitsDual);*/
7863 
7864     Automs = AutomorphismGroup<Integer>(ExtremeRays, SupportHyperplanes, SpecialLinFoprms);
7865 
7866     Automs.compute(AutomParam::euclidean);
7867 
7868     if (verbose)
7869         verboseOutput() << Automs.getQualitiesString() << "automorphism group of order " << Automs.getOrder() << "  done" << endl;
7870 
7871     extract_automorphisms(Automs);
7872 
7873     setComputed(ConeProperty::EuclideanAutomorphisms);
7874 }
7875 
7876 //---------------------------------------------------------------------------
7877 template <typename Integer>
7878 template <typename IntegerFC>
extract_automorphisms(AutomorphismGroup<IntegerFC> & AutomsComputed,const bool must_transform)7879 void Cone<Integer>::extract_automorphisms(AutomorphismGroup<IntegerFC>& AutomsComputed, const bool must_transform){
7880 
7881     Automs.order = AutomsComputed.order;
7882     Automs.is_integral = AutomsComputed.is_integral;
7883     Automs.integrality_checked = AutomsComputed.integrality_checked;
7884     Automs.Qualities = AutomsComputed.Qualities;
7885 
7886     vector<key_t> SuppHypsKey, ExtRaysKey, VerticesKey, GensKey;
7887 
7888     Automs.GenPerms = extract_permutations(AutomsComputed.GenPerms, AutomsComputed.GensRef, ExtremeRays, true, GensKey, must_transform);
7889 
7890     Automs.ExtRaysPerms.clear(); // not necessarily set below
7891     if (inhomogeneous) {
7892 
7893         if(ExtremeRaysRecCone.nr_of_rows() >0 ){
7894             Automs.ExtRaysPerms =
7895                     extract_permutations(AutomsComputed.GenPerms, AutomsComputed.GensRef, ExtremeRaysRecCone, true, ExtRaysKey, must_transform);
7896         }
7897         Automs.VerticesPerms =
7898             extract_permutations(AutomsComputed.GenPerms, AutomsComputed.GensRef, VerticesOfPolyhedron, true, VerticesKey, must_transform);
7899     }
7900     else {
7901         Automs.ExtRaysPerms = Automs.GenPerms;
7902         ExtRaysKey = GensKey;
7903     }
7904 
7905     Automs.LinFormPerms =
7906         extract_permutations(AutomsComputed.LinFormPerms, AutomsComputed.LinFormsRef, SupportHyperplanes, false, SuppHypsKey, must_transform);
7907     Automs.SuppHypsPerms = Automs.LinFormPerms;
7908 
7909     Automs.GenOrbits = extract_subsets(AutomsComputed.GenOrbits, AutomsComputed.GensRef.nr_of_rows(), GensKey);
7910 
7911     sort_individual_vectors(Automs.GenOrbits);
7912     if (inhomogeneous) {
7913         Automs.VerticesOrbits = extract_subsets(AutomsComputed.GenOrbits, AutomsComputed.GensRef.nr_of_rows(), VerticesKey);
7914         sort_individual_vectors(Automs.VerticesOrbits);
7915         Automs.ExtRaysOrbits.clear(); // not necessarily set below
7916         if(ExtremeRaysRecCone.nr_of_rows() >0 ){
7917             Automs.ExtRaysOrbits = extract_subsets(AutomsComputed.GenOrbits, AutomsComputed.GensRef.nr_of_rows(), ExtRaysKey);
7918             sort_individual_vectors(Automs.ExtRaysOrbits);
7919         }
7920     }
7921     else {
7922         Automs.ExtRaysOrbits = Automs.GenOrbits;
7923     }
7924 
7925     Automs.LinFormOrbits = extract_subsets(AutomsComputed.LinFormOrbits, AutomsComputed.LinFormsRef.nr_of_rows(), SuppHypsKey);
7926     sort_individual_vectors(Automs.LinFormOrbits);
7927     Automs.SuppHypsOrbits = Automs.LinFormOrbits;
7928 
7929     Automs.cone_dependent_data_computed = true;
7930 
7931 }
7932 //---------------------------------------------------------------------------
7933 template <typename Integer>
compute_pulling_triangulation(ConeProperties & ToCompute)7934 void Cone<Integer>::compute_pulling_triangulation(ConeProperties& ToCompute){
7935 
7936     if(isComputed(ConeProperty::PullingTriangulation))
7937             return;
7938 
7939     if(verbose)
7940         verboseOutput() << "Computing pulling triangulation" << endl;
7941 
7942     // BasicTriangulation is the only data field to get a triangulation from the full_cone.
7943     // This will be the pulling triangulation.
7944     // Therefore an existing basic triangulation must be saved and restired.
7945     pair<vector<SHORTSIMPLEX<Integer> >, Matrix<Integer> > SaveBasicTriangulation;
7946     bool save_is_computed_BasicTriangulation = isComputed(ConeProperty::BasicTriangulation);
7947     if(isComputed(ConeProperty::BasicTriangulation))
7948         swap(BasicTriangulation, SaveBasicTriangulation);
7949 
7950     ConeProperties PullTri;
7951     PullTri.set(ConeProperty::PullingTriangulationInternal);
7952     compute_full_cone(PullTri);
7953     Triangulation = BasicTriangulation;
7954     setComputed(ConeProperty::Triangulation);
7955     setComputed(ConeProperty::PullingTriangulationInternal);
7956     setComputed(ConeProperty::PullingTriangulation);
7957 
7958     is_Computed.set(ConeProperty::BasicTriangulation, save_is_computed_BasicTriangulation);
7959     if(isComputed(ConeProperty::BasicTriangulation))
7960         swap(BasicTriangulation, SaveBasicTriangulation);
7961 }
7962 
7963 //---------------------------------------------------------------------------
7964 template <typename Integer>
compute_refined_triangulation(ConeProperties & ToCompute)7965 void Cone<Integer>::compute_refined_triangulation(ConeProperties& ToCompute){
7966 
7967     if( ToCompute.intersection_with(all_triangulations()).none() )
7968         return;
7969 
7970     if(ToCompute.test(ConeProperty::PullingTriangulation)){
7971         compute_pulling_triangulation(ToCompute);
7972         return;
7973     }
7974 
7975 
7976     compute(ConeProperty::BasicTriangulation); // we need it here
7977 
7978     // First we deal with the ordinary triangulation
7979     if(ToCompute.test(ConeProperty::Triangulation)){
7980         Triangulation = BasicTriangulation;
7981         setComputed(ConeProperty::Triangulation);
7982         return;
7983     }
7984 
7985     is_Computed.reset(ConeProperty::ConeDecomposition);
7986 
7987     if (change_integer_type) {
7988         try {
7989 #ifdef NMZ_EXTENDED_TESTS
7990             if(!using_GMP<Integer>() && !using_renf<Integer>() && test_arith_overflow_descent)
7991                 throw ArithmeticException(0);
7992 #endif
7993             compute_unimodular_triangulation<MachineInteger>(ToCompute); // only one can be actiated
7994             compute_lattice_point_triangulation<MachineInteger>(ToCompute);
7995             compute_all_generators_triangulation<MachineInteger>(ToCompute);
7996         } catch (const ArithmeticException& e) {
7997             if (verbose) {
7998                 verboseOutput() << e.what() << endl;
7999                 verboseOutput() << "Restarting with a bigger type." << endl;
8000             }
8001             change_integer_type = false;
8002         }
8003     }
8004     if (! change_integer_type) {
8005         compute_unimodular_triangulation<Integer>(ToCompute); // only one can be actiated
8006         compute_lattice_point_triangulation<Integer>(ToCompute);
8007         compute_all_generators_triangulation<Integer>(ToCompute);
8008     }
8009 }
8010 
8011 template <typename Integer>
8012 template <typename IntegerColl>
prepare_collection(ConeCollection<IntegerColl> & Coll)8013 void Cone<Integer>::prepare_collection(ConeCollection<IntegerColl>& Coll){
8014 
8015     compute(ConeProperty::BasicTriangulation);
8016 
8017     BasisChangePointed.convert_to_sublattice(Coll.Generators,BasicTriangulation.second);
8018     vector<pair<vector<key_t>, IntegerColl> > CollTriangulation;
8019     for(auto& T: BasicTriangulation.first){
8020         IntegerColl CollMult = convertTo<IntegerColl>(T.vol);
8021         CollTriangulation.push_back(make_pair(T.key, CollMult));
8022     }
8023     Coll.verbose = verbose;
8024     Coll.initialize_minicones(CollTriangulation);
8025 }
8026 
8027 template <typename Integer>
8028 template <typename IntegerColl>
extract_data(ConeCollection<IntegerColl> & Coll)8029 void Cone<Integer>::extract_data(ConeCollection<IntegerColl>& Coll){
8030 
8031     BasisChangePointed.convert_from_sublattice(Triangulation.second, Coll.Generators);
8032     Triangulation.first.clear();
8033     Coll.flatten();
8034     for(auto& T: Coll.getKeysAndMult()){
8035 
8036         INTERRUPT_COMPUTATION_BY_EXCEPTION
8037 
8038         Integer CollMult = convertTo<Integer>(T.second);
8039         SHORTSIMPLEX<Integer> Simp;
8040         Simp.key = T.first;
8041         Simp.vol = CollMult;
8042         Triangulation.first.push_back(Simp);
8043     }
8044 #ifdef NMZ_EXTENDED_TESTS
8045     if(isComputed(ConeProperty::Volume)  && !using_renf<Integer>()){
8046         mpq_class test_vol;
8047         vector<Integer> TestGrad;
8048         if(inhomogeneous)
8049             TestGrad = Dehomogenization;
8050         else
8051             TestGrad = Grading;
8052         for(auto& T: Triangulation.first){
8053             Integer grad_prod = 1;
8054             for(auto& k: T.key)
8055                 grad_prod *= v_scalar_product(Triangulation.second[k], TestGrad);
8056             mpz_class gp_mpz = convertTo<mpz_class>(grad_prod);
8057             mpz_class vol_mpz = convertTo<mpz_class>(T.vol);
8058             mpq_class quot = vol_mpz;
8059             quot /= gp_mpz;
8060             test_vol+=quot;
8061         }
8062         assert(test_vol == getVolume());
8063     }
8064 #endif
8065 }
8066 
8067 template <typename Integer>
8068 template <typename IntegerColl>
compute_unimodular_triangulation(ConeProperties & ToCompute)8069 void Cone<Integer>::compute_unimodular_triangulation(ConeProperties& ToCompute){
8070 
8071     if(!ToCompute.test(ConeProperty::UnimodularTriangulation) || isComputed(ConeProperty::UnimodularTriangulation))
8072         return;
8073 
8074     if(verbose)
8075         verboseOutput() << "Computing unimimodular triangulation" << endl;
8076 
8077     ConeCollection<IntegerColl> UMT;
8078     prepare_collection<IntegerColl>(UMT);
8079     if(isComputed(ConeProperty::HilbertBasis)){
8080         Matrix<IntegerColl> HBPointed;
8081         BasisChangePointed.convert_to_sublattice(HBPointed,HilbertBasis);
8082         UMT.add_extra_generators(HBPointed);
8083     }
8084 
8085     UMT.make_unimodular();
8086     extract_data<IntegerColl>(UMT);
8087     setComputed(ConeProperty::UnimodularTriangulation);
8088     setComputed(ConeProperty::Triangulation );
8089 }
8090 
8091 template<>
8092 template <typename IntegerColl>
compute_unimodular_triangulation(ConeProperties & ToCompute)8093 void Cone<renf_elem_class>::compute_unimodular_triangulation(ConeProperties& ToCompute){
8094 
8095     if(!ToCompute.test(ConeProperty::UnimodularTriangulation) || isComputed(ConeProperty::UnimodularTriangulation))
8096         return;
8097 
8098     assert(false);
8099 }
8100 
8101 template <typename Integer>
8102 template <typename IntegerColl>
compute_lattice_point_triangulation(ConeProperties & ToCompute)8103 void Cone<Integer>::compute_lattice_point_triangulation(ConeProperties& ToCompute){
8104 
8105     if(!ToCompute.test(ConeProperty::LatticePointTriangulation) || isComputed(ConeProperty::LatticePointTriangulation))
8106         return;
8107 
8108     if(inhomogeneous && getNrExtremeRays() >0)
8109         throw BadInputException("LatticePointTriangulation not defined for unbounded polyhedra");
8110 
8111     if(verbose)
8112         verboseOutput() << "Computing lattice points triangulation" << endl;
8113 
8114     ConeCollection<IntegerColl> LPT;
8115     prepare_collection<IntegerColl>(LPT);
8116     Matrix<IntegerColl> LPPointed;
8117     if(inhomogeneous){
8118         assert(isComputed(ConeProperty::ModuleGenerators));
8119         BasisChangePointed.convert_to_sublattice(LPPointed,ModuleGenerators);
8120     }
8121     else{
8122         assert(isComputed(ConeProperty::Deg1Elements));
8123         BasisChangePointed.convert_to_sublattice(LPPointed,Deg1Elements);
8124     }
8125     LPT.add_extra_generators(LPPointed);
8126     extract_data<IntegerColl>(LPT);
8127     setComputed(ConeProperty::LatticePointTriangulation);
8128     setComputed(ConeProperty::Triangulation);
8129 }
8130 
8131 template <typename Integer>
8132 template <typename IntegerColl>
compute_all_generators_triangulation(ConeProperties & ToCompute)8133 void Cone<Integer>::compute_all_generators_triangulation(ConeProperties& ToCompute){
8134 
8135     if(!ToCompute.test(ConeProperty::AllGeneratorsTriangulation) || isComputed(ConeProperty::AllGeneratorsTriangulation))
8136         return;
8137 
8138     if(verbose)
8139         verboseOutput() << "Computing all generators triangulation" << endl;
8140 
8141     ConeCollection<IntegerColl> OMT;
8142     prepare_collection<IntegerColl>(OMT);
8143     Matrix<IntegerColl> OMPointed;
8144     BasisChangePointed.convert_to_sublattice(OMPointed,InputGenerators);
8145     OMT.insert_all_gens();
8146     extract_data<IntegerColl>(OMT);
8147     setComputed(ConeProperty::AllGeneratorsTriangulation);
8148     setComputed(ConeProperty::Triangulation );
8149 }
8150 
8151 //---------------------------------------------------------------------------
8152 
8153 template <typename Integer>
resetProjectionCoords(const vector<Integer> & lf)8154 void Cone<Integer>::resetProjectionCoords(const vector<Integer>& lf) {
8155 
8156     if(ProjCone != NULL)
8157         delete ProjCone;
8158 
8159     if(lf.size() > dim)
8160         throw BadInputException("Too many projection coordinates");
8161     projection_coord_indicator.resize(dim);
8162     for (size_t i = 0; i < lf.size(); ++i)
8163         if (lf[i] != 0)
8164             projection_coord_indicator[i] = true;
8165 }
8166 
8167 //---------------------------------------------------------------------------
8168 
8169 template <typename Integer>
resetGrading(vector<Integer> lf)8170 void Cone<Integer>::resetGrading(vector<Integer> lf) {
8171     is_Computed.reset(ConeProperty::HilbertSeries);
8172     is_Computed.reset(ConeProperty::HSOP);
8173     is_Computed.reset(ConeProperty::HilbertQuasiPolynomial);
8174     is_Computed.reset(ConeProperty::EhrhartSeries);
8175     is_Computed.reset(ConeProperty::EhrhartQuasiPolynomial);
8176     is_Computed.reset(ConeProperty::WeightedEhrhartSeries);
8177     is_Computed.reset(ConeProperty::WeightedEhrhartQuasiPolynomial);
8178     is_Computed.reset(ConeProperty::Integral);
8179     is_Computed.reset(ConeProperty::EuclideanIntegral);
8180     is_Computed.reset(ConeProperty::Multiplicity);
8181     is_Computed.reset(ConeProperty::VirtualMultiplicity);
8182     is_Computed.reset(ConeProperty::Grading);
8183     is_Computed.reset(ConeProperty::GradingDenom);
8184     is_Computed.reset(ConeProperty::IsDeg1ExtremeRays);
8185     // is_Computed.reset(ConeProperty::ExplicitHilbertSeries);
8186     is_Computed.reset(ConeProperty::IsDeg1HilbertBasis);
8187     is_Computed.reset(ConeProperty::Deg1Elements);
8188     if (!inhomogeneous) {
8189         is_Computed.reset(ConeProperty::Volume);
8190         is_Computed.reset(ConeProperty::EuclideanVolume);
8191         if (isComputed(ConeProperty::IntegerHull))
8192             delete IntHullCone;
8193         is_Computed.reset(ConeProperty::IntegerHull);
8194     }
8195 
8196     if (inhom_input) {
8197         lf.push_back(0);
8198     }
8199     setGrading(lf);
8200 }
8201 
8202 // Multi-getter methods
8203 template <typename Integer>
getMatrixConePropertyMatrix(ConeProperty::Enum property)8204 const Matrix<Integer>& Cone<Integer>::getMatrixConePropertyMatrix(ConeProperty::Enum property) {
8205     if (output_type(property) != OutputType::Matrix) {
8206         throw FatalException("property has no matrix output");
8207     }
8208     switch (property) {
8209         case ConeProperty::ExtremeRays:
8210             return this->getExtremeRaysMatrix();
8211         case ConeProperty::VerticesOfPolyhedron:
8212             return this->getVerticesOfPolyhedronMatrix();
8213         case ConeProperty::SupportHyperplanes:
8214             return this->getSupportHyperplanesMatrix();
8215         case ConeProperty::HilbertBasis:
8216             return this->getHilbertBasisMatrix();
8217         case ConeProperty::ModuleGenerators:
8218             return this->getModuleGeneratorsMatrix();
8219         case ConeProperty::Deg1Elements:
8220             return this->getDeg1ElementsMatrix();
8221         case ConeProperty::LatticePoints:
8222             return this->getLatticePointsMatrix();
8223         case ConeProperty::ModuleGeneratorsOverOriginalMonoid:
8224             return this->getModuleGeneratorsOverOriginalMonoidMatrix();
8225         case ConeProperty::ExcludedFaces:
8226             return this->getExcludedFacesMatrix();
8227         case ConeProperty::OriginalMonoidGenerators:
8228             return this->getOriginalMonoidGeneratorsMatrix();
8229         case ConeProperty::MaximalSubspace:
8230             return this->getMaximalSubspaceMatrix();
8231         // The following point to the sublattice
8232         case ConeProperty::Equations:
8233             return this->getSublattice().getEquationsMatrix();
8234         case ConeProperty::Congruences:
8235             return this->getSublattice().getCongruencesMatrix();
8236         default:
8237             throw FatalException("Matrix property without output");
8238     }
8239 }
8240 
8241 template <typename Integer>
getMatrixConeProperty(ConeProperty::Enum property)8242 const vector<vector<Integer> >& Cone<Integer>::getMatrixConeProperty(ConeProperty::Enum property) {
8243     return getMatrixConePropertyMatrix(property).get_elements();
8244 }
8245 
8246 template <typename Integer>
getFloatMatrixConePropertyMatrix(ConeProperty::Enum property)8247 const Matrix<nmz_float>& Cone<Integer>::getFloatMatrixConePropertyMatrix(ConeProperty::Enum property) {
8248     if (output_type(property) != OutputType::MatrixFloat) {
8249         throw FatalException("property has no float matrix output");
8250     }
8251     switch (property) {
8252         case ConeProperty::SuppHypsFloat:
8253             return this->getSuppHypsFloatMatrix();
8254         case ConeProperty::ExtremeRaysFloat:
8255             return this->getSuppHypsFloatMatrix();
8256         case ConeProperty::VerticesFloat:
8257             return this->getVerticesFloatMatrix();
8258         default:
8259             throw FatalException("Flaot Matrix property without output");
8260     }
8261 }
8262 
8263 template <typename Integer>
getFloatMatrixConeProperty(ConeProperty::Enum property)8264 const vector<vector<nmz_float> >& Cone<Integer>::getFloatMatrixConeProperty(ConeProperty::Enum property) {
8265     return getFloatMatrixConePropertyMatrix(property).get_elements();
8266 }
8267 
8268 template <typename Integer>
getVectorConeProperty(ConeProperty::Enum property)8269 vector<Integer> Cone<Integer>::getVectorConeProperty(ConeProperty::Enum property) {
8270     if (output_type(property) != OutputType::Vector) {
8271         throw FatalException("property has no vector output");
8272     }
8273     switch (property) {
8274         case ConeProperty::Grading:
8275             return this->getGrading();
8276         case ConeProperty::Dehomogenization:
8277             return this->getDehomogenization();
8278         case ConeProperty::WitnessNotIntegrallyClosed:
8279             return this->getWitnessNotIntegrallyClosed();
8280         case ConeProperty::GeneratorOfInterior:
8281             return this->getGeneratorOfInterior();
8282         case ConeProperty::CoveringFace:
8283             return this->getCoveringFace();
8284         case ConeProperty::AxesScaling:
8285             return this->getAxesScaling();
8286         default:
8287             throw FatalException("Vector property without output");
8288     }
8289 }
8290 
8291 template <typename Integer>
getIntegerConeProperty(ConeProperty::Enum property)8292 Integer Cone<Integer>::getIntegerConeProperty(ConeProperty::Enum property) {
8293     if (output_type(property) != OutputType::Integer) {
8294         throw FatalException("property has no integer output");
8295     }
8296     switch (property) {
8297         case ConeProperty::TriangulationDetSum:
8298             return this->getTriangulationDetSum();
8299         case ConeProperty::ReesPrimaryMultiplicity:
8300             return this->getReesPrimaryMultiplicity();
8301         case ConeProperty::GradingDenom:
8302             return this->getGradingDenom();
8303         case ConeProperty::UnitGroupIndex:
8304             return this->getUnitGroupIndex();
8305         case ConeProperty::InternalIndex:
8306             return this->getInternalIndex();
8307         default:
8308             throw FatalException("Intehger property without output");;
8309     }
8310 }
8311 
8312 template <typename Integer>
getGMPIntegerConeProperty(ConeProperty::Enum property)8313 mpz_class Cone<Integer>::getGMPIntegerConeProperty(ConeProperty::Enum property) {
8314     if (output_type(property) != OutputType::GMPInteger) {
8315         throw FatalException("property has no GMP integer output");
8316     }
8317     switch (property) {
8318         case ConeProperty::ExternalIndex:
8319             return this->getSublattice().getExternalIndex();
8320         default:
8321             throw FatalException("GMP integer property without output");
8322     }
8323 }
8324 
8325 template <typename Integer>
getRationalConeProperty(ConeProperty::Enum property)8326 mpq_class Cone<Integer>::getRationalConeProperty(ConeProperty::Enum property) {
8327     if (output_type(property) != OutputType::Rational) {
8328         throw FatalException("property has no rational output");
8329     }
8330     switch (property) {
8331         case ConeProperty::Multiplicity:
8332             return this->getMultiplicity();
8333         case ConeProperty::Volume:
8334             return this->getVolume();
8335         case ConeProperty::Integral:
8336             return this->getIntegral();
8337         case ConeProperty::VirtualMultiplicity:
8338             return this->getVirtualMultiplicity();
8339         default:
8340             throw FatalException("Rational property without output");;
8341     }
8342 }
8343 
8344 template <typename Integer>
getFieldElemConeProperty(ConeProperty::Enum property)8345 renf_elem_class Cone<Integer>::getFieldElemConeProperty(ConeProperty::Enum property) {
8346     if (output_type(property) != OutputType::FieldElem) {
8347         throw FatalException("property has no field element output");
8348     }
8349     switch (property) {
8350         case ConeProperty::RenfVolume:
8351             return this->getRenfVolume();
8352         default:
8353             throw FatalException("Field element property without output");;
8354     }
8355 }
8356 
8357 template <typename Integer>
getFloatConeProperty(ConeProperty::Enum property)8358 nmz_float Cone<Integer>::getFloatConeProperty(ConeProperty::Enum property) {
8359     if (output_type(property) != OutputType::Float) {
8360         throw FatalException("property has no float output");
8361     }
8362     switch (property) {
8363         case ConeProperty::EuclideanVolume:
8364             return this->getEuclideanVolume();
8365         case ConeProperty::EuclideanIntegral:
8366             return this->getEuclideanIntegral();
8367         default:
8368             throw FatalException("Float property without output");;
8369     }
8370 }
8371 
8372 template <typename Integer>
getMachineIntegerConeProperty(ConeProperty::Enum property)8373 long Cone<Integer>::getMachineIntegerConeProperty(ConeProperty::Enum property) {
8374     if (output_type(property) != OutputType::MachineInteger) {
8375         throw FatalException("property has no machine integer output");
8376     }
8377     switch (property) {
8378         case ConeProperty::TriangulationSize:
8379             return this->getTriangulationSize();
8380         case ConeProperty::RecessionRank:
8381             return this->getRecessionRank();
8382         case ConeProperty::AffineDim:
8383             return this->getAffineDim();
8384         case ConeProperty::ModuleRank:
8385             return this->getModuleRank();
8386         case ConeProperty::Rank:
8387             return this->getRank();
8388         case ConeProperty::EmbeddingDim:
8389             return this->getEmbeddingDim();
8390         case ConeProperty::NumberLatticePoints:
8391             return this->getNumberLatticePoints();
8392         default:
8393             throw FatalException("Machine integer property without output");
8394     }
8395 }
8396 
8397 template <typename Integer>
getBooleanConeProperty(ConeProperty::Enum property)8398 bool Cone<Integer>::getBooleanConeProperty(ConeProperty::Enum property) {
8399     if (output_type(property) != OutputType::Bool) {
8400         throw FatalException("property has no boolean output");
8401     }
8402     switch (property) {
8403         case ConeProperty::IsPointed:
8404             return this->isPointed();
8405         case ConeProperty::IsDeg1ExtremeRays:
8406             return this->isDeg1ExtremeRays();
8407         case ConeProperty::IsDeg1HilbertBasis:
8408             return this->isDeg1HilbertBasis();
8409         case ConeProperty::IsIntegrallyClosed:
8410             return this->isIntegrallyClosed();
8411         case ConeProperty::IsReesPrimary:
8412             return this->isReesPrimary();
8413         case ConeProperty::IsInhomogeneous:
8414             return this->isInhomogeneous();
8415         case ConeProperty::IsGorenstein:
8416             return this->isGorenstein();
8417         case ConeProperty::IsEmptySemiOpen:
8418             return this->isEmptySemiOpen();
8419         case ConeProperty::IsTriangulationNested:
8420             return this->isTriangulationNested();
8421         case ConeProperty::IsTriangulationPartial:
8422             return this->isTriangulationPartial();
8423         default:
8424             throw FatalException("Boolean property without output");
8425     }
8426 }
8427 
8428 template <typename Integer>
write_cone_output(const string & output_file)8429 void Cone<Integer>::write_cone_output(const string& output_file) {
8430     Output<Integer> Out;
8431 
8432     Out.set_name(output_file); // one could take if from the cone in output.cpp
8433 
8434     // Out.set_lattice_ideal_input(input.count(Type::lattice_ideal)>0);
8435 
8436     Out.setCone(*this);
8437 #ifdef ENFNORMALIZ
8438     Out.set_renf(Renf);
8439 #endif
8440 
8441     Out.write_files();
8442 }
8443 
8444 #ifndef NMZ_MIC_OFFLOAD  // offload with long is not supported
8445 template class Cone<long>;
8446 #endif
8447 template class Cone<long long>;
8448 template class Cone<mpz_class>;
8449 
8450 #ifdef ENFNORMALIZ
8451 template class Cone<renf_elem_class>;
8452 #endif
8453 
8454 #ifdef NMZ_EXTENDED_TESTS
8455 // additional tests for libnormaliz that are not accessoble from Normaliz
run_additional_tests_libnormaliz()8456 void run_additional_tests_libnormaliz(){
8457 
8458     vector<nmz_float> ext_1 ={ 1.0, 1.5};
8459     vector<nmz_float> ext_2 ={ 3.1e1, 1.7e1};
8460     vector<vector<nmz_float> > test_ext = {ext_1, ext_2};
8461     Matrix<nmz_float> test_input(test_ext);
8462 
8463     Cone<mpz_class> C(Type::polytope, test_input);
8464     // C.getHilbertBasisMatrix().pretty_print(cout);
8465 
8466     vector<mpz_class> new_grading = {1,2,3};
8467     C.resetGrading(new_grading);
8468     C.compute(ConeProperty::HilbertSeries);
8469 
8470     C.getAutomorphismGroup(ConeProperty::CombinatorialAutomorphisms);
8471 
8472     C.getOriginalMonoidGenerators();
8473 
8474     C.getMaximalSubspace();
8475 
8476     C.getExtremeRays();
8477 
8478     C.getSuppHypsFloat();
8479 
8480     C.getNrSuppHypsFloat();
8481 
8482     C.getSupportHyperplanes();
8483     C.getNrSupportHyperplanes();
8484 
8485     C.getEquations();
8486     C.getNrEquations();
8487 
8488     C.getCongruences();
8489     C.getNrCongruences();
8490 
8491     C.getHilbertBasis();
8492 
8493     C.getModuleGeneratorsOverOriginalMonoid();
8494 
8495     C.getDeg1Elements();
8496 
8497     C.getLatticePointsMatrix();
8498 
8499     C.getLatticePoints();
8500 
8501     C.getNrLatticePoints();
8502 
8503     C.isPointed();
8504 
8505     C.getTriangulation(ConeProperty::UnimodularTriangulation);
8506     C.getTriangulation(ConeProperty::LatticePointTriangulation);
8507     C.getTriangulation(ConeProperty::AllGeneratorsTriangulation);
8508 
8509     vector<vector<nmz_float> > eq = {{-1,1,-1}};
8510 
8511     C.modifyCone(Type::equations,eq);
8512 
8513     C = Cone<mpz_class>(Type::vertices, test_input);
8514 
8515     C.getVerticesFloat();
8516     C.getNrVerticesFloat();
8517     C.getVerticesOfPolyhedron();
8518     C.getModuleGenerators();
8519     C.getExtremeRaysFloat();
8520     C.getExtremeRaysFloatMatrix();
8521     C.getNrExtremeRaysFloat();
8522 
8523     vector<vector<mpz_class> > trivial = {{-1,1},{1,1}};
8524     vector<vector<mpz_class> > excl = {{-1,1}};
8525     C = Cone<mpz_class>(Type::cone, trivial, Type::excluded_faces,excl);
8526     C.getHilbertSeries();
8527     C.compute(ConeProperty::HSOP);
8528 
8529     C.getExcludedFaces();
8530 
8531     C = Cone<mpz_class>(Type::polytope, trivial);
8532     C.getLatticePoints();
8533 
8534     Isomorphism_Classes<mpz_class> IsoC;
8535     bool found;
8536     IsoC.add_type(C, found);
8537     IsoC.find_type(C, found);
8538 
8539 }
8540 #endif
8541 
8542 }  // end namespace libnormaliz
8543