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