CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

| Download

GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it

Views: 418384
1
/*
2
* Normaliz
3
* Copyright (C) 2007-2014 Winfried Bruns, Bogdan Ichim, Christof Soeger
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation, either version 3 of the License, or
7
* (at your option) any later version.
8
*
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
13
*
14
* You should have received a copy of the GNU General Public License
15
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
*
17
* As an exception, when this program is distributed through (i) the App Store
18
* by Apple Inc.; (ii) the Mac App Store by Apple Inc.; or (iii) Google Play
19
* by Google Inc., then that store may impose any digital rights management,
20
* device limits and/or redistribution restrictions that are required by its
21
* terms of service.
22
*/
23
24
//---------------------------------------------------------------------------
25
26
#include <stdlib.h>
27
#include <set>
28
#include <map>
29
#include <iostream>
30
#include <string>
31
#include <algorithm>
32
#include <time.h>
33
#include <deque>
34
35
#include "libQnormaliz/Qfull_cone.h"
36
#include "libQnormaliz/Qcone_helper.h"
37
#include "libQnormaliz/Qvector_operations.h"
38
#include "libQnormaliz/Qlist_operations.h"
39
#include "libQnormaliz/Qmap_operations.h"
40
#include "libQnormaliz/Qmy_omp.h"
41
#include "libQnormaliz/Qinteger.h"
42
// #include "libQnormaliz/Qsublattice_representation.h"
43
// #include "libQnormaliz/Qoffload_handler.h"
44
45
//---------------------------------------------------------------------------
46
47
// const size_t RecBoundTriang=1000000; // if number(supphyps)*size(triang) > RecBoundTriang
48
// we pass to (non-recirsive) pyramids
49
// now in build_cone
50
51
const size_t EvalBoundTriang=2500000; // if more than EvalBoundTriang simplices have been stored
52
// evaluation is started (whenever possible)
53
54
const size_t EvalBoundPyr=200000; // the same for stored pyramids of level > 0
55
56
const size_t EvalBoundLevel0Pyr=200000; // 1000000; // the same for stored level 0 pyramids
57
58
// const size_t EvalBoundRecPyr=200000; // the same for stored RECURSIVE pyramids
59
60
// const size_t IntermedRedBoundHB=2000000; // bound for number of HB elements before
61
// intermediate reduction is called
62
63
const int largePyramidFactor=20; // pyramid is large if largePyramidFactor*Comparisons[Pyramid_key.size()-dim] > old_nr_supp_hyps
64
65
const int SuppHypRecursionFactor=200; // pyramids for supphyps formed if Pos*Neg > this factor*dim^4
66
67
const size_t RAM_Size=1000000000; // we assume that there is at least 1 GB of RAM
68
69
const long GMP_time_factor=20; // factor by which GMP arithmetic differs from long long
70
71
//---------------------------------------------------------------------------
72
73
namespace libQnormaliz {
74
using namespace std;
75
76
//---------------------------------------------------------------------------
77
//private
78
//---------------------------------------------------------------------------
79
80
template<typename Number>
81
void Full_Cone<Number>::check_simpliciality_hyperplane(const FACETDATA& hyp) const{
82
size_t nr_gen_in_hyp=0;
83
for(size_t i=0; i<nr_gen;++i)
84
if(in_triang[i]&& hyp.GenInHyp.test(i))
85
nr_gen_in_hyp++;
86
if((hyp.simplicial && nr_gen_in_hyp!=dim-2) || (!hyp.simplicial && nr_gen_in_hyp==dim-2)){
87
// NOTE: in_triang set at END of main loop in build_cone
88
cout << "Simplicial " << hyp.simplicial << " dim " << dim << " gen_in_hyp " << nr_gen_in_hyp << endl;
89
assert(false);
90
}
91
}
92
93
template<typename Number>
94
void Full_Cone<Number>::set_simplicial(FACETDATA& hyp){
95
size_t nr_gen_in_hyp=0;
96
for(size_t i=0; i<nr_gen;++i)
97
if(in_triang[i]&& hyp.GenInHyp.test(i))
98
nr_gen_in_hyp++;
99
hyp.simplicial=(nr_gen_in_hyp==dim-2);
100
}
101
102
template<typename Number>
103
void Full_Cone<Number>::number_hyperplane(FACETDATA& hyp, const size_t born_at, const size_t mother){
104
// add identifying number, the birth day and the number of mother
105
106
hyp.Mother=mother;
107
hyp.BornAt=born_at;
108
if(!multithreaded_pyramid){
109
hyp.Ident=HypCounter[0];
110
HypCounter[0]++;
111
return;
112
}
113
114
int tn;
115
if(omp_get_level()==0)
116
tn=0;
117
else
118
tn = omp_get_ancestor_thread_num(1);
119
hyp.Ident=HypCounter[tn];
120
HypCounter[tn]+=omp_get_max_threads();
121
122
}
123
124
//---------------------------------------------------------------------------
125
126
template<typename Number>
127
bool Full_Cone<Number>::is_hyperplane_included(FACETDATA& hyp) {
128
if (!is_pyramid) { // in the topcone we always have ov_sp > 0
129
return true;
130
}
131
//check if it would be an excluded hyperplane
132
Number ov_sp = v_scalar_product(hyp.Hyp,Order_Vector);
133
if (ov_sp > 0) {
134
return true;
135
} else if (ov_sp == 0) {
136
for (size_t i=0; i<dim; i++) {
137
if (hyp.Hyp[i]>0) {
138
return true;
139
} else if (hyp.Hyp[i]<0) {
140
return false;
141
}
142
}
143
}
144
return false;
145
}
146
147
//---------------------------------------------------------------------------
148
149
template<typename Number>
150
void Full_Cone<Number>::add_hyperplane(const size_t& new_generator, const FACETDATA & positive,const FACETDATA & negative,
151
list<FACETDATA>& NewHyps, bool known_to_be_simplicial){
152
// adds a new hyperplane found in find_new_facets to this cone (restricted to generators processed)
153
154
size_t k;
155
156
FACETDATA NewFacet; NewFacet.Hyp.resize(dim); NewFacet.GenInHyp.resize(nr_gen);
157
158
for (k = 0; k <dim; k++) {
159
NewFacet.Hyp[k]=positive.ValNewGen*negative.Hyp[k]-negative.ValNewGen*positive.Hyp[k];
160
if(!check_range(NewFacet.Hyp[k]))
161
break;
162
}
163
164
/* cout << "==========================================" << endl;
165
cout << NewFacet.Hyp;
166
cout << "==========================================" << endl; */
167
168
v_simplify(NewFacet.Hyp);
169
170
NewFacet.ValNewGen=0;
171
NewFacet.GenInHyp=positive.GenInHyp & negative.GenInHyp; // new hyperplane contains old gen iff both pos and neg do
172
if(known_to_be_simplicial){
173
NewFacet.simplicial=true;
174
check_simpliciality_hyperplane(NewFacet);
175
}
176
else
177
set_simplicial(NewFacet);
178
NewFacet.GenInHyp.set(new_generator); // new hyperplane contains new generator
179
number_hyperplane(NewFacet,nrGensInCone,positive.Ident);
180
181
NewHyps.push_back(NewFacet);
182
}
183
184
185
//---------------------------------------------------------------------------
186
187
188
template<typename Number>
189
void Full_Cone<Number>::find_new_facets(const size_t& new_generator){
190
// our Fourier-Motzkin implementation
191
// the special treatment of simplicial facets was inserted because of line shellings.
192
// At present these are not computed.
193
194
//to see if possible to replace the function .end with constant iterator since push-back is performed.
195
196
// for dimension 0 and 1 F-M is never necessary and can lead to problems
197
// when using dim-2
198
if (dim <= 1)
199
return;
200
201
// NEW: new_generator is the index of the generator being inserted
202
203
size_t i,k,nr_zero_i;
204
size_t subfacet_dim=dim-2; // NEW dimension of subfacet
205
size_t facet_dim=dim-1; // NEW dimension of facet
206
207
const bool tv_verbose = false; //verbose && !is_pyramid; // && Support_Hyperplanes.nr_of_rows()>10000; //verbose in this method call
208
209
210
// preparing the computations, the various types of facets are sorted into the deques
211
deque <FACETDATA*> Pos_Simp,Pos_Non_Simp;
212
deque <FACETDATA*> Neg_Simp,Neg_Non_Simp;
213
deque <FACETDATA*> Neutral_Simp, Neutral_Non_Simp;
214
215
boost::dynamic_bitset<> Zero_Positive(nr_gen),Zero_Negative(nr_gen); // here we collect the vertices that lie in a
216
// postive resp. negative hyperplane
217
218
bool simplex;
219
220
if (tv_verbose) verboseOutput()<<"transform_values:"<<flush;
221
222
typename list<FACETDATA>::iterator ii = Facets.begin();
223
224
for (; ii != Facets.end(); ++ii) {
225
// simplex=true;
226
// nr_zero_i=0;
227
simplex=ii->simplicial; // at present simplicial, will become nonsimplicial if neutral
228
/* for (size_t j=0; j<nr_gen; j++){
229
if (ii->GenInHyp.test(j)) {
230
if (++nr_zero_i > facet_dim) {
231
simplex=false;
232
break;
233
}
234
}
235
}*/
236
237
if (ii->ValNewGen==0) {
238
ii->GenInHyp.set(new_generator); // Must be set explicitly !!
239
ii->simplicial=false; // simpliciality definitly gone with the new generator
240
if (simplex) {
241
Neutral_Simp.push_back(&(*ii)); // simplicial without the new generator
242
} else {
243
Neutral_Non_Simp.push_back(&(*ii)); // nonsim�plicial already without the new generator
244
}
245
}
246
else if (ii->ValNewGen>0) {
247
Zero_Positive |= ii->GenInHyp;
248
if (simplex) {
249
Pos_Simp.push_back(&(*ii));
250
} else {
251
Pos_Non_Simp.push_back(&(*ii));
252
}
253
}
254
else if (ii->ValNewGen<0) {
255
Zero_Negative |= ii->GenInHyp;
256
if (simplex) {
257
Neg_Simp.push_back(&(*ii));
258
} else {
259
Neg_Non_Simp.push_back(&(*ii));
260
}
261
}
262
}
263
264
// TO DO: Negativliste mit Zero_Positive verfeinern, also die aussondern, die nicht genug positive Erz enthalten
265
// Eventuell sogar Rang-Test einbauen.
266
// Letzteres könnte man auch bei den positiven machen, bevor sie verarbeitet werden
267
268
boost::dynamic_bitset<> Zero_PN(nr_gen);
269
Zero_PN = Zero_Positive & Zero_Negative;
270
271
size_t nr_PosSimp = Pos_Simp.size();
272
size_t nr_PosNonSimp = Pos_Non_Simp.size();
273
size_t nr_NegSimp = Neg_Simp.size();
274
size_t nr_NegNonSimp = Neg_Non_Simp.size();
275
size_t nr_NeuSimp = Neutral_Simp.size();
276
size_t nr_NeuNonSimp = Neutral_Non_Simp.size();
277
278
if (tv_verbose) verboseOutput()<<" PS "<<nr_PosSimp<<", P "<<nr_PosNonSimp<<", NS "<<nr_NegSimp<<", N "<<nr_NegNonSimp<<", ZS "<<nr_NeuSimp<<", Z "<<nr_NeuNonSimp<<endl;
279
280
if (tv_verbose) verboseOutput()<<"transform_values: subfacet of NS: "<<flush;
281
282
vector< list<pair < boost::dynamic_bitset<>, int> > > Neg_Subfacet_Multi(omp_get_max_threads()) ;
283
284
boost::dynamic_bitset<> zero_i, subfacet;
285
286
// This parallel region cannot throw a NormalizException
287
#pragma omp parallel for private(zero_i,subfacet,k,nr_zero_i)
288
for (i=0; i<nr_NegSimp;i++){
289
zero_i=Zero_PN & Neg_Simp[i]->GenInHyp;
290
291
nr_zero_i=0;
292
for(size_t j=0;j<nr_gen;j++){
293
if(zero_i.test(j))
294
nr_zero_i++;
295
if(nr_zero_i>subfacet_dim){
296
break;
297
}
298
}
299
300
if(nr_zero_i==subfacet_dim) // NEW This case treated separately
301
Neg_Subfacet_Multi[omp_get_thread_num()].push_back(pair <boost::dynamic_bitset<>, int> (zero_i,i));
302
303
if(nr_zero_i==facet_dim){
304
for (k =0; k<nr_gen; k++) {
305
if(zero_i.test(k)) {
306
subfacet=zero_i;
307
subfacet.reset(k); // remove k-th element from facet to obtain subfacet
308
Neg_Subfacet_Multi[omp_get_thread_num()].push_back(pair <boost::dynamic_bitset<>, int> (subfacet,i));
309
}
310
}
311
}
312
}
313
314
list < pair < boost::dynamic_bitset<>, int> > Neg_Subfacet_Multi_United;
315
for(int i=0;i<omp_get_max_threads();++i)
316
Neg_Subfacet_Multi_United.splice(Neg_Subfacet_Multi_United.begin(),Neg_Subfacet_Multi[i]);
317
Neg_Subfacet_Multi_United.sort();
318
319
320
if (tv_verbose) verboseOutput()<<Neg_Subfacet_Multi_United.size() << ", " << flush;
321
322
list< pair < boost::dynamic_bitset<>, int > >::iterator jj;
323
list< pair < boost::dynamic_bitset<>, int > >::iterator del;
324
jj =Neg_Subfacet_Multi_United.begin(); // remove negative subfacets shared
325
while (jj!= Neg_Subfacet_Multi_United.end()) { // by two neg simpl facets
326
del=jj++;
327
if (jj!=Neg_Subfacet_Multi_United.end() && (*jj).first==(*del).first) { //delete since is the intersection of two negative simplicies
328
Neg_Subfacet_Multi_United.erase(del);
329
del=jj++;
330
Neg_Subfacet_Multi_United.erase(del);
331
}
332
}
333
334
size_t nr_NegSubfMult = Neg_Subfacet_Multi_United.size();
335
if (tv_verbose) verboseOutput() << nr_NegSubfMult << ", " << flush;
336
337
vector<list<FACETDATA> > NewHypsSimp(nr_PosSimp);
338
vector<list<FACETDATA> > NewHypsNonSimp(nr_PosNonSimp);
339
340
map < boost::dynamic_bitset<>, int > Neg_Subfacet;
341
size_t nr_NegSubf=0;
342
343
// size_t NrMatches=0, NrCSF=0, NrRank=0, NrComp=0, NrNewF=0;
344
345
/* deque<bool> Indi(nr_NegNonSimp);
346
for(size_t j=0;j<nr_NegNonSimp;++j)
347
Indi[j]=false; */
348
349
if(multithreaded_pyramid){
350
#pragma omp atomic
351
nrTotalComparisons+=nr_NegNonSimp*nr_PosNonSimp;
352
}
353
else{
354
nrTotalComparisons+=nr_NegNonSimp*nr_PosNonSimp;
355
}
356
357
358
//=====================================================================
359
// parallel from here
360
361
bool skip_remaining = false;
362
#ifndef NCATCH
363
std::exception_ptr tmp_exception;
364
#endif
365
366
#pragma omp parallel private(jj)
367
{
368
size_t i,j,k,nr_zero_i;
369
boost::dynamic_bitset<> subfacet(dim-2);
370
jj = Neg_Subfacet_Multi_United.begin();
371
size_t jjpos=0;
372
int tn = omp_get_ancestor_thread_num(1);
373
374
bool found;
375
// This for region cannot throw a NormalizException
376
#pragma omp for schedule(dynamic)
377
for (size_t j=0; j<nr_NegSubfMult; ++j) { // remove negative subfacets shared
378
for(;j > jjpos; ++jjpos, ++jj) ; // by non-simpl neg or neutral facets
379
for(;j < jjpos; --jjpos, --jj) ;
380
381
subfacet=(*jj).first;
382
found=false;
383
for (i = 0; i <nr_NeuSimp; i++) {
384
found=subfacet.is_subset_of(Neutral_Simp[i]->GenInHyp);
385
if(found)
386
break;
387
}
388
if (!found) {
389
for (i = 0; i <nr_NeuNonSimp; i++) {
390
found=subfacet.is_subset_of(Neutral_Non_Simp[i]->GenInHyp);
391
if(found)
392
break;
393
}
394
if(!found) {
395
for (i = 0; i <nr_NegNonSimp; i++) {
396
found=subfacet.is_subset_of(Neg_Non_Simp[i]->GenInHyp);
397
if(found)
398
break;
399
}
400
}
401
}
402
if (found) {
403
jj->second=-1;
404
}
405
}
406
407
#pragma omp single
408
{ //remove elements that where found in the previous loop
409
jj = Neg_Subfacet_Multi_United.begin();
410
map < boost::dynamic_bitset<>, int > ::iterator last_inserted=Neg_Subfacet.begin(); // used to speedup insertion into the new map
411
for (; jj!= Neg_Subfacet_Multi_United.end(); ++jj) {
412
if ((*jj).second != -1) {
413
last_inserted = Neg_Subfacet.insert(last_inserted,*jj);
414
}
415
}
416
nr_NegSubf=Neg_Subfacet.size();
417
}
418
419
#pragma omp single nowait
420
{Neg_Subfacet_Multi_United.clear();}
421
422
423
boost::dynamic_bitset<> zero_i(nr_gen);
424
map <boost::dynamic_bitset<>, int> ::iterator jj_map;
425
426
427
#pragma omp single nowait
428
if (tv_verbose) {
429
verboseOutput() << "PS vs NS and PS vs N , " << flush;
430
}
431
432
vector<key_t> key(nr_gen);
433
size_t nr_missing;
434
bool common_subfacet;
435
// we cannot use nowait here because of the way we handle exceptions in this loop
436
#pragma omp for schedule(dynamic) //nowait
437
for (size_t i =0; i<nr_PosSimp; i++){
438
439
if (skip_remaining) continue;
440
#ifndef NCATCH
441
try {
442
#endif
443
zero_i=Zero_PN & Pos_Simp[i]->GenInHyp;
444
nr_zero_i=0;
445
for(j=0;j<nr_gen && nr_zero_i<=facet_dim;j++)
446
if(zero_i.test(j)){
447
key[nr_zero_i]=j;
448
nr_zero_i++;
449
}
450
451
if(nr_zero_i<subfacet_dim)
452
continue;
453
454
// first PS vs NS
455
456
if (nr_zero_i==subfacet_dim) { // NEW slight change in logic. Positive simpl facet shared at most
457
jj_map=Neg_Subfacet.find(zero_i); // one subfacet with negative simpl facet
458
if (jj_map!=Neg_Subfacet.end()) {
459
add_hyperplane(new_generator,*Pos_Simp[i],*Neg_Simp[(*jj_map).second],NewHypsSimp[i],true);
460
(*jj_map).second = -1; // block subfacet in further searches
461
}
462
}
463
if (nr_zero_i==facet_dim){ // now there could be more such subfacets. We make all and search them.
464
for (k =0; k<nr_gen; k++) { // BOOST ROUTINE
465
if(zero_i.test(k)) {
466
subfacet=zero_i;
467
subfacet.reset(k); // remove k-th element from facet to obtain subfacet
468
jj_map=Neg_Subfacet.find(subfacet);
469
if (jj_map!=Neg_Subfacet.end()) {
470
add_hyperplane(new_generator,*Pos_Simp[i],*Neg_Simp[(*jj_map).second],NewHypsSimp[i],true);
471
(*jj_map).second = -1;
472
// Indi[j]=true;
473
}
474
}
475
}
476
}
477
478
// now PS vs N
479
480
for (j=0; j<nr_NegNonSimp; j++){ // search negative facet with common subfacet
481
nr_missing=0;
482
common_subfacet=true;
483
for(k=0;k<nr_zero_i;k++) {
484
if(!Neg_Non_Simp[j]->GenInHyp.test(key[k])) {
485
nr_missing++;
486
if(nr_missing==2 || nr_zero_i==subfacet_dim) {
487
common_subfacet=false;
488
break;
489
}
490
}
491
}
492
493
if(common_subfacet){
494
add_hyperplane(new_generator,*Pos_Simp[i],*Neg_Non_Simp[j],NewHypsSimp[i],true);
495
if(nr_zero_i==subfacet_dim) // only one subfacet can lie in negative hyperplane
496
break;
497
}
498
}
499
#ifndef NCATCH
500
} catch(const std::exception& ) {
501
tmp_exception = std::current_exception();
502
skip_remaining = true;
503
#pragma omp flush(skip_remaining)
504
}
505
#endif
506
507
} // PS vs NS and PS vs N
508
509
if (!skip_remaining) {
510
#pragma omp single nowait
511
if (tv_verbose) {
512
verboseOutput() << "P vs NS and P vs N" << endl;
513
}
514
515
list<FACETDATA*> AllNonSimpHyp;
516
typename list<FACETDATA*>::iterator a;
517
518
for(i=0;i<nr_PosNonSimp;++i)
519
AllNonSimpHyp.push_back(&(*Pos_Non_Simp[i]));
520
for(i=0;i<nr_NegNonSimp;++i)
521
AllNonSimpHyp.push_back(&(*Neg_Non_Simp[i]));
522
for(i=0;i<nr_NeuNonSimp;++i)
523
AllNonSimpHyp.push_back(&(*Neutral_Non_Simp[i]));
524
size_t nr_NonSimp = nr_PosNonSimp+nr_NegNonSimp+nr_NeuNonSimp;
525
526
bool ranktest;
527
FACETDATA *hp_i, *hp_j, *hp_t; // pointers to current hyperplanes
528
529
size_t missing_bound, nr_common_zero;
530
boost::dynamic_bitset<> common_zero(nr_gen);
531
vector<key_t> common_key;
532
common_key.reserve(nr_gen);
533
vector<int> key_start(nrGensInCone);
534
535
#pragma omp for schedule(dynamic) // nowait
536
for (size_t i =0; i<nr_PosNonSimp; i++){ //Positive Non Simp vs.Negative Simp and Non Simp
537
538
if (skip_remaining) continue;
539
540
#ifndef NCATCH
541
try {
542
#endif
543
jj_map = Neg_Subfacet.begin(); // First the Simp
544
for (j=0; j<nr_NegSubf; ++j,++jj_map) {
545
if ( (*jj_map).second != -1 ) { // skip used subfacets
546
if(jj_map->first.is_subset_of(Pos_Non_Simp[i]->GenInHyp)){
547
add_hyperplane(new_generator,*Pos_Non_Simp[i],*Neg_Simp[(*jj_map).second],NewHypsNonSimp[i],true);
548
(*jj_map).second = -1; // has now been used
549
}
550
}
551
}
552
553
// Now the NonSimp
554
555
hp_i=Pos_Non_Simp[i];
556
zero_i=Zero_PN & hp_i->GenInHyp; // these are the potential vertices in an intersection
557
nr_zero_i=0;
558
int last_existing=-1;
559
for(size_t jj=0;jj<nrGensInCone;jj++) // we make a "key" of the potential vertices in the intersection
560
{
561
j=GensInCone[jj];
562
if(zero_i.test(j)){
563
key[nr_zero_i]=j;
564
for(size_t kk= last_existing+1;kk<=jj;kk++) // used in the extension test
565
key_start[kk]=nr_zero_i; // to find out from which generator on both have existed
566
nr_zero_i++;
567
last_existing= jj;
568
}
569
}
570
if(last_existing< (int)nrGensInCone-1)
571
for(size_t kk=last_existing+1;kk<nrGensInCone;kk++)
572
key_start[kk]=nr_zero_i;
573
574
if (nr_zero_i<subfacet_dim)
575
continue;
576
577
// now nr_zero_i is the number of vertices in hp_i that have a chance to lie in a negative facet
578
// and key contains the indices
579
580
missing_bound=nr_zero_i-subfacet_dim; // at most this number of generators can be missing
581
// to have a chance for common subfacet
582
583
for (j=0; j<nr_NegNonSimp; j++){
584
585
586
hp_j=Neg_Non_Simp[j];
587
588
if(hp_i->Ident==hp_j->Mother || hp_j->Ident==hp_i->Mother){ // mother and daughter coming together
589
add_hyperplane(new_generator,*hp_i,*hp_j,NewHypsNonSimp[i],false); // their intersection is a subfacet
590
continue; // simplicial set in add_hyperplane
591
}
592
593
594
bool extension_test=hp_i->BornAt==hp_j->BornAt || (hp_i->BornAt<hp_j->BornAt && hp_j->Mother!=0)
595
|| (hp_j->BornAt<hp_i->BornAt && hp_i->Mother!=0);
596
597
// extension_test=false;
598
599
size_t both_existing_from=key_start[max(hp_i->BornAt,hp_j->BornAt)];
600
601
nr_missing=0;
602
nr_common_zero=0;
603
common_key.clear();
604
size_t second_loop_bound=nr_zero_i;
605
common_subfacet=true;
606
607
// We use the following criterion:
608
// if the two facets are not mother and daughter (taken care of already), then
609
// they cannot have intersected in a subfacet at the time when the second was born.
610
// In other words: they can only intersect in a subfacet now, if at least one common vertex
611
// has been added after the birth of the younger one.
612
// this is indicated by "extended".
613
614
if(extension_test){
615
bool extended=false;
616
second_loop_bound=both_existing_from; // fisrt we find the common vertices inserted from the step
617
// where both facets existed the first time
618
for(k=both_existing_from;k<nr_zero_i;k++){
619
if(!hp_j->GenInHyp.test(key[k])) {
620
nr_missing++;
621
if(nr_missing>missing_bound) {
622
common_subfacet=false;
623
break;
624
}
625
}
626
else {
627
extended=true; // in this case they have a common vertex added after their common existence
628
common_key.push_back(key[k]);
629
nr_common_zero++;
630
}
631
}
632
633
if(!extended || !common_subfacet) //
634
continue;
635
}
636
637
638
for(k=0;k<second_loop_bound;k++) { // now the remaining
639
if(!hp_j->GenInHyp.test(key[k])) {
640
nr_missing++;
641
if(nr_missing>missing_bound) {
642
common_subfacet=false;
643
break;
644
}
645
}
646
else {
647
common_key.push_back(key[k]);
648
nr_common_zero++;
649
}
650
}
651
652
if(!common_subfacet)
653
continue;
654
/* #pragma omp atomic
655
NrCSF++;*/
656
657
if(using_GMP<Number>())
658
ranktest = (nr_NonSimp > GMP_time_factor*dim*dim*nr_common_zero/3); // in this case the rank computation takes longer
659
else
660
ranktest = (nr_NonSimp > dim*dim*nr_common_zero/3);
661
662
if(ranktest) {
663
664
// cout << "Rangtest" << endl;
665
666
/* #pragma omp atomic
667
NrRank++; */
668
669
Matrix<Number>& Test = Top_Cone->RankTest[tn];
670
if (Test.rank_submatrix(Generators,common_key)<subfacet_dim) {
671
common_subfacet=false;
672
}
673
} // ranktest
674
else{ // now the comparison test
675
676
/* #pragma omp atomic
677
NrComp++; */
678
679
common_zero = zero_i & hp_j->GenInHyp;
680
for (a=AllNonSimpHyp.begin();a!=AllNonSimpHyp.end();++a){
681
hp_t=*a;
682
if ((hp_t!=hp_i) && (hp_t!=hp_j) && common_zero.is_subset_of(hp_t->GenInHyp)) {
683
common_subfacet=false;
684
AllNonSimpHyp.splice(AllNonSimpHyp.begin(),AllNonSimpHyp,a); // for the "darwinistic" mewthod
685
break;
686
}
687
}
688
} // else
689
if (common_subfacet) { //intersection of i and j is a subfacet
690
add_hyperplane(new_generator,*hp_i,*hp_j,NewHypsNonSimp[i],false); //simplicial set in add_hyperplane
691
/* #pragma omp atomic
692
NrNewF++; */
693
// Indi[j]=true;
694
}
695
}
696
#ifndef NCATCH
697
} catch(const std::exception& ) {
698
tmp_exception = std::current_exception();
699
skip_remaining = true;
700
#pragma omp flush(skip_remaining)
701
}
702
#endif
703
} // end for
704
} // end !skip_remaining
705
} //END parallel
706
707
#ifndef NCATCH
708
if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);
709
#endif
710
//=====================================================================
711
// parallel until here
712
713
714
/* if(!is_pyramid)
715
cout << "Matches " << NrMatches << " pot. common subf " << NrCSF << " rank test " << NrRank << " comp test "
716
<< NrComp << " neww hyps " << NrNewF << endl; */
717
718
719
for(i=0;i<nr_PosSimp;i++)
720
Facets.splice(Facets.end(),NewHypsSimp[i]);
721
722
for(i=0;i<nr_PosNonSimp;i++)
723
Facets.splice(Facets.end(),NewHypsNonSimp[i]);
724
725
//removing the negative hyperplanes
726
// now done in build_cone
727
728
if (tv_verbose) verboseOutput()<<"transform_values: done"<<endl;
729
730
}
731
732
//---------------------------------------------------------------------------
733
734
template<typename Number>
735
void Full_Cone<Number>::extend_triangulation(const size_t& new_generator){
736
// extends the triangulation of this cone by including new_generator
737
// simplicial facets save us from searching the "brother" in the existing triangulation
738
// to which the new simplex gets attached
739
740
size_t listsize =old_nr_supp_hyps; // Facets.size();
741
vector<typename list<FACETDATA>::iterator> visible;
742
visible.reserve(listsize);
743
typename list<FACETDATA>::iterator i = Facets.begin();
744
745
listsize=0;
746
for (; i!=Facets.end(); ++i)
747
if (i->ValNewGen < 0){ // visible facet
748
visible.push_back(i);
749
listsize++;
750
}
751
752
#ifndef NCATCH
753
std::exception_ptr tmp_exception;
754
#endif
755
756
typename list< SHORTSIMPLEX<Number> >::iterator oldTriBack = --TriangulationBuffer.end();
757
#pragma omp parallel private(i)
758
{
759
size_t k,l;
760
bool one_not_in_i, not_in_facet;
761
size_t not_in_i=0;
762
// size_t facet_dim=dim-1;
763
// size_t nr_in_i=0;
764
765
list< SHORTSIMPLEX<Number> > Triangulation_kk;
766
typename list< SHORTSIMPLEX<Number> >::iterator j;
767
768
vector<key_t> key(dim);
769
770
// if we only want a partial triangulation but came here because of a deep level
771
// mark if this part of the triangulation has not to be evaluated
772
bool skip_eval = false;
773
774
#pragma omp for schedule(dynamic)
775
for (size_t kk=0; kk<listsize; ++kk) {
776
777
#ifndef NCATCH
778
try {
779
#endif
780
i=visible[kk];
781
782
/* nr_in_i=0;
783
for(size_t m=0;m<nr_gen;m++){
784
if(i->GenInHyp.test(m))
785
nr_in_i++;
786
if(nr_in_i>facet_dim){
787
break;
788
}
789
}*/
790
791
skip_eval = Top_Cone->do_partial_triangulation && i->ValNewGen == -1
792
&& is_hyperplane_included(*i);
793
794
if (i->simplicial){ // simplicial
795
l=0;
796
for (k = 0; k <nr_gen; k++) {
797
if (i->GenInHyp[k]==1) {
798
key[l]=k;
799
l++;
800
}
801
}
802
key[dim-1]=new_generator;
803
804
if (skip_eval)
805
store_key(key,0,0,Triangulation_kk);
806
else
807
store_key(key,-i->ValNewGen,0,Triangulation_kk);
808
continue;
809
} // end simplicial
810
811
size_t irrelevant_vertices=0;
812
for(size_t vertex=0;vertex<nrGensInCone;++vertex){
813
814
if(i->GenInHyp[GensInCone[vertex]]==0) // lead vertex not in hyperplane
815
continue;
816
817
if(irrelevant_vertices<dim-2){
818
++irrelevant_vertices;
819
continue;
820
}
821
822
j=TriSectionFirst[vertex];
823
bool done=false;
824
for(;!done;j++)
825
{
826
done=(j==TriSectionLast[vertex]);
827
key=j->key;
828
one_not_in_i=false; // true indicates that one gen of simplex is not in hyperplane
829
not_in_facet=false; // true indicates that a second gen of simplex is not in hyperplane
830
for(k=0;k<dim;k++){
831
if ( !i->GenInHyp.test(key[k])) {
832
if(one_not_in_i){
833
not_in_facet=true;
834
break;
835
}
836
one_not_in_i=true;
837
not_in_i=k;
838
}
839
}
840
841
if(not_in_facet) // simplex does not share facet with hyperplane
842
continue;
843
844
key[not_in_i]=new_generator;
845
if (skip_eval)
846
store_key(key,0,j->vol,Triangulation_kk);
847
else
848
store_key(key,-i->ValNewGen,j->vol,Triangulation_kk);
849
850
} // j
851
852
} // for vertex
853
854
#ifndef NCATCH
855
} catch(const std::exception& ) {
856
tmp_exception = std::current_exception();
857
}
858
#endif
859
860
} // omp for kk
861
862
if (multithreaded_pyramid) {
863
#pragma omp critical(TRIANG)
864
TriangulationBuffer.splice(TriangulationBuffer.end(),Triangulation_kk);
865
} else
866
TriangulationBuffer.splice(TriangulationBuffer.end(),Triangulation_kk);
867
868
} // parallel
869
870
#ifndef NCATCH
871
if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);
872
#endif
873
874
// GensInCone.push_back(new_generator); // now in extend_cone
875
TriSectionFirst.push_back(++oldTriBack);
876
TriSectionLast.push_back(--TriangulationBuffer.end());
877
}
878
879
//---------------------------------------------------------------------------
880
881
template<typename Number>
882
void Full_Cone<Number>::store_key(const vector<key_t>& key, const Number& height,
883
const Number& mother_vol, list< SHORTSIMPLEX<Number> >& Triangulation){
884
// stores a simplex given by key and height in Triangulation
885
// mother_vol is the volume of the simplex to which the new one is attached
886
887
SHORTSIMPLEX<Number> newsimplex;
888
newsimplex.key=key;
889
newsimplex.height=height;
890
newsimplex.vol=0;
891
892
if(multithreaded_pyramid){
893
#pragma omp atomic
894
TriangulationBufferSize++;
895
}
896
else {
897
TriangulationBufferSize++;
898
}
899
int tn;
900
if(omp_get_level()==0)
901
tn=0;
902
else
903
tn = omp_get_ancestor_thread_num(1);
904
905
if (height == 0) Top_Cone->triangulation_is_partial = true;
906
907
if (keep_triangulation){
908
Triangulation.push_back(newsimplex);
909
return;
910
}
911
912
bool Simpl_available=true;
913
914
typename list< SHORTSIMPLEX<Number> >::iterator F;
915
916
if(Top_Cone->FS[tn].empty()){
917
if (Top_Cone->FreeSimpl.empty()) {
918
Simpl_available=false;
919
} else {
920
#pragma omp critical(FREESIMPL)
921
{
922
if (Top_Cone->FreeSimpl.empty()) {
923
Simpl_available=false;
924
} else {
925
// take 1000 simplices from FreeSimpl or what you can get
926
F = Top_Cone->FreeSimpl.begin();
927
size_t q;
928
for (q = 0; q < 1000; ++q, ++F) {
929
if (F == Top_Cone->FreeSimpl.end())
930
break;
931
}
932
933
if(q<1000)
934
Top_Cone->FS[tn].splice(Top_Cone->FS[tn].begin(),
935
Top_Cone->FreeSimpl);
936
else
937
Top_Cone->FS[tn].splice(Top_Cone->FS[tn].begin(),
938
Top_Cone->FreeSimpl,Top_Cone->FreeSimpl.begin(),F);
939
} // if empty global (critical)
940
} // critical
941
} // if empty global
942
} // if empty thread
943
944
if (Simpl_available) {
945
Triangulation.splice(Triangulation.end(),Top_Cone->FS[tn],
946
Top_Cone->FS[tn].begin());
947
Triangulation.back() = newsimplex;
948
} else {
949
Triangulation.push_back(newsimplex);
950
}
951
}
952
953
//---------------------------------------------------------------------------
954
955
template<typename Number>
956
void Full_Cone<Number>::process_pyramids(const size_t new_generator,const bool recursive){
957
958
/*
959
960
We distinguish two types of pyramids:
961
962
(i) recursive pyramids that give their support hyperplanes back to the mother.
963
(ii) independent pyramids that are not linked to the mother.
964
965
The parameter "recursive" indicates whether the pyramids that will be created
966
in process_pyramid(s) are of type (i) or (ii).
967
968
Every pyramid can create subpyramids of both types (not the case in version 2.8 - 2.10).
969
970
Whether "this" is of type (i) or (ii) is indicated by do_all_hyperplanes.
971
972
The creation of (sub)pyramids of type (i) can be blocked by setting recursion_allowed=false.
973
(Not done in this version.)
974
975
is_pyramid==false for the top_cone and ==true else.
976
977
multithreaded_pyramid indicates whether parallelization takes place within the
978
computation of a pyramid or whether it is computed in a single thread (defined in build_cone).
979
980
Recursie pyramids are processed immediately after creation (as in 2.8). However, there
981
are two exceptions:
982
983
(a) In order to avoid very long waiting times for the computation of the "large" ones,
984
these are treated as follows: the support hyperplanes of "this" coming from their bases
985
(as negative hyperplanes of "this") are computed by matching them with the
986
positive hyperplanes of "this". This Fourier-Motzkin step is much more
987
efficient if a pyramid is large. For triangulation a large recursive
988
pyramid is then stored as a pyramid of type (ii).
989
990
(b) If "this" is processed in a parallelized loop calling process_pyramids, then
991
the loop in process_pyramids cannot be interrupted for the evaluation of simplices. As a
992
consequence an extremely long lst of simplices could arise if many small subpyramids of "this"
993
are created in process_pyramids. In order to prevent this dangeous effect, small recursive
994
subpyramids are stored for later triangulation if the simplex buffer has reached its
995
size bound.
996
997
Pyramids of type (ii) are stpred in Pyramids. The store_level of the created pyramids is 0
998
for all pyramids created (possibly recursively) from the top cone. Pyramids created
999
in evaluate_stored_pyramids get the store level for their subpyramids in that routine and
1000
transfer it to their recursive daughters. (correction March 4, 2015).
1001
1002
Note: the top cone has pyr_level=-1. The pyr_level has no algorithmic relevance
1003
at present, but it shows the depth of the pyramid recursion at which the pyramid has been
1004
created.
1005
1006
*/
1007
1008
1009
size_t start_level=omp_get_level(); // allows us to check that we are on level 0
1010
// outside the loop and can therefore call evaluation
1011
// in order to empty the buffers
1012
vector<key_t> Pyramid_key;
1013
Pyramid_key.reserve(nr_gen);
1014
bool skip_triang; // make hyperplanes but skip triangulation (recursive pyramids only)
1015
1016
deque<bool> done(old_nr_supp_hyps,false);
1017
bool skip_remaining;
1018
#ifndef NCATCH
1019
std::exception_ptr tmp_exception;
1020
#endif
1021
typename list< FACETDATA >::iterator hyp;
1022
size_t nr_done=0;
1023
1024
do{ // repeats processing until all hyperplanes have been processed
1025
1026
hyp=Facets.begin();
1027
size_t hyppos=0;
1028
skip_remaining = false;
1029
1030
const long VERBOSE_STEPS = 50;
1031
long step_x_size = old_nr_supp_hyps-VERBOSE_STEPS;
1032
const size_t RepBound=10000;
1033
1034
#pragma omp parallel for private(skip_triang) firstprivate(hyppos,hyp,Pyramid_key) schedule(dynamic) reduction(+: nr_done)
1035
for (size_t kk=0; kk<old_nr_supp_hyps; ++kk) {
1036
1037
if (skip_remaining) continue;
1038
1039
if(verbose && old_nr_supp_hyps>=RepBound){
1040
#pragma omp critical(VERBOSE)
1041
while ((long)(kk*VERBOSE_STEPS) >= step_x_size) {
1042
step_x_size += old_nr_supp_hyps;
1043
verboseOutput() << "." <<flush;
1044
}
1045
}
1046
1047
#ifndef NCATCH
1048
try {
1049
#endif
1050
for(;kk > hyppos; hyppos++, hyp++) ;
1051
for(;kk < hyppos; hyppos--, hyp--) ;
1052
1053
if(done[hyppos])
1054
continue;
1055
1056
done[hyppos]=true;
1057
1058
nr_done++;
1059
1060
if (hyp->ValNewGen == 0){ // MUST BE SET HERE
1061
hyp->GenInHyp.set(new_generator);
1062
if(recursive) hyp->simplicial=false; // in the recursive case
1063
}
1064
1065
if (hyp->ValNewGen >= 0) // facet not visible
1066
continue;
1067
1068
skip_triang = false;
1069
if (Top_Cone->do_partial_triangulation && hyp->ValNewGen>=-1) { //ht1 criterion
1070
skip_triang = is_hyperplane_included(*hyp);
1071
if (skip_triang) {
1072
Top_Cone->triangulation_is_partial = true;
1073
if (!recursive) {
1074
continue;
1075
}
1076
}
1077
}
1078
1079
Pyramid_key.clear(); // make data of new pyramid
1080
Pyramid_key.push_back(new_generator);
1081
for(size_t i=0;i<nr_gen;i++){
1082
if(in_triang[i] && hyp->GenInHyp.test(i)) {
1083
Pyramid_key.push_back(i);
1084
}
1085
}
1086
1087
// now we can store the new pyramid at the right place (or finish the simplicial ones)
1088
if (recursive && skip_triang) { // mark as "do not triangulate"
1089
process_pyramid(Pyramid_key, new_generator,store_level,0, recursive,hyp,start_level);
1090
} else { //default
1091
process_pyramid(Pyramid_key, new_generator,store_level,-hyp->ValNewGen, recursive,hyp,start_level);
1092
}
1093
// interrupt parallel execution if it is really parallel
1094
// to keep the triangulationand pyramid buffers under control
1095
if (start_level==0) {
1096
if (check_evaluation_buffer_size() || Top_Cone->check_pyr_buffer(store_level)) {
1097
skip_remaining = true;
1098
}
1099
}
1100
1101
#ifndef NCATCH
1102
} catch(const std::exception& ) {
1103
tmp_exception = std::current_exception();
1104
skip_remaining = true;
1105
#pragma omp flush(skip_remaining)
1106
}
1107
#endif
1108
} // end parallel loop over hyperplanes
1109
1110
#ifndef NCATCH
1111
if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);
1112
#endif
1113
1114
if (start_level==0 && check_evaluation_buffer_size()) {
1115
Top_Cone->evaluate_triangulation();
1116
}
1117
1118
if (start_level==0 && Top_Cone->check_pyr_buffer(store_level)) {
1119
Top_Cone->evaluate_stored_pyramids(store_level);
1120
}
1121
1122
if (verbose && old_nr_supp_hyps>=RepBound)
1123
verboseOutput() << endl;
1124
1125
} while (nr_done < old_nr_supp_hyps);
1126
1127
1128
evaluate_large_rec_pyramids(new_generator);
1129
1130
}
1131
1132
//---------------------------------------------------------------------------
1133
1134
template<typename Number>
1135
void Full_Cone<Number>::process_pyramid(const vector<key_t>& Pyramid_key,
1136
const size_t new_generator,const size_t store_level, Number height, const bool recursive,
1137
typename list< FACETDATA >::iterator hyp, size_t start_level){
1138
// processes simplicial pyramids directly, stores other pyramids into their depots
1139
1140
#pragma omp atomic
1141
Top_Cone->totalNrPyr++;
1142
1143
if(Pyramid_key.size()==dim){ // simplicial pyramid completely done here
1144
#pragma omp atomic // only for saving memory
1145
Top_Cone->nrSimplicialPyr++;
1146
if(recursive){ // the facets may be facets of the mother cone and if recursive==true must be given back
1147
Matrix<Number> H(dim,dim);
1148
Number dummy_vol;
1149
Generators.simplex_data(Pyramid_key,H, dummy_vol,false);
1150
list<FACETDATA> NewFacets;
1151
FACETDATA NewFacet;
1152
NewFacet.GenInHyp.resize(nr_gen);
1153
for (size_t i=0; i<dim;i++) {
1154
NewFacet.Hyp = H[i];
1155
NewFacet.GenInHyp.set();
1156
NewFacet.GenInHyp.reset(i);
1157
NewFacet.simplicial=true;
1158
NewFacets.push_back(NewFacet);
1159
}
1160
select_supphyps_from(NewFacets,new_generator,Pyramid_key); // takes itself care of multithreaded_pyramid
1161
}
1162
if (height != 0 && (do_triangulation || do_partial_triangulation)) {
1163
if(multithreaded_pyramid) {
1164
#ifndef NCATCH
1165
std::exception_ptr tmp_exception;
1166
#endif
1167
#pragma omp critical(TRIANG)
1168
{
1169
#ifndef NCATCH
1170
try{
1171
#endif
1172
store_key(Pyramid_key,height,0,TriangulationBuffer);
1173
nrTotalComparisons+=dim*dim/2;
1174
#ifndef NCATCH
1175
} catch(const std::exception& ) {
1176
tmp_exception = std::current_exception();
1177
}
1178
#endif
1179
} // end critical
1180
#ifndef NCATCH
1181
if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);
1182
#endif
1183
} else {
1184
store_key(Pyramid_key,height,0,TriangulationBuffer);
1185
nrTotalComparisons+=dim*dim/2;
1186
}
1187
}
1188
}
1189
else { // non-simplicial
1190
1191
bool large=(largePyramidFactor*Comparisons[Pyramid_key.size()-dim] > old_nr_supp_hyps); // Pyramid_key.size()>largePyramidFactor*dim;
1192
1193
if (!recursive || (large && (do_triangulation || do_partial_triangulation) && height!=0) ) { // must also store for triangulation if recursive and large
1194
vector<key_t> key_wrt_top(Pyramid_key.size());
1195
for(size_t i=0;i<Pyramid_key.size();i++)
1196
key_wrt_top[i]=Top_Key[Pyramid_key[i]];
1197
#pragma omp critical(STOREPYRAMIDS)
1198
{
1199
// cout << "store_level " << store_level << " large " << large << " pyr level " << pyr_level << endl;
1200
Top_Cone->Pyramids[store_level].push_back(key_wrt_top);
1201
Top_Cone->nrPyramids[store_level]++;
1202
} // critical
1203
if(!recursive) // in this case we need only store for future triangulation, and that has been done
1204
return;
1205
}
1206
// now we are in the recursive case and must compute support hyperplanes of the subpyramid
1207
if(large){ // large recursive pyramid
1208
if(multithreaded_pyramid){
1209
#pragma omp critical(LARGERECPYRS)
1210
LargeRecPyrs.push_back(*hyp); // LargeRecPyrs are kept and evaluated locally
1211
}
1212
else
1213
LargeRecPyrs.push_back(*hyp);
1214
return; // done with the large recusive pyramids
1215
}
1216
1217
// only recursive small ones left
1218
1219
Full_Cone<Number> Pyramid(*this,Pyramid_key);
1220
Pyramid.Mother = this;
1221
Pyramid.Mother_Key = Pyramid_key; // need these data to give back supphyps
1222
Pyramid.apex=new_generator;
1223
if (height == 0) { //indicates "do not triangulate"
1224
Pyramid.do_triangulation = false;
1225
Pyramid.do_partial_triangulation = false;
1226
// Pyramid.do_Hilbert_basis = false;
1227
// Pyramid.do_deg1_elements=false;
1228
}
1229
1230
bool store_for_triangulation=(store_level!=0) //loop in process_pyramids cannot be interrupted
1231
&& (Pyramid.do_triangulation || Pyramid.do_partial_triangulation) // we must (partially) triangulate
1232
&& (start_level!=0 && Top_Cone->TriangulationBufferSize > 2*EvalBoundTriang); // evaluation buffer already full // EvalBoundTriang
1233
1234
if (store_for_triangulation) {
1235
vector<key_t> key_wrt_top(Pyramid_key.size());
1236
for(size_t i=0;i<Pyramid_key.size();i++)
1237
key_wrt_top[i]=Top_Key[Pyramid_key[i]];
1238
#pragma omp critical(STOREPYRAMIDS)
1239
{
1240
Top_Cone->Pyramids[store_level].push_back(key_wrt_top);
1241
Top_Cone->nrPyramids[store_level]++;
1242
} // critical
1243
// Now we must suppress immediate triangulation
1244
Pyramid.do_triangulation = false;
1245
Pyramid.do_partial_triangulation = false;
1246
// Pyramid.do_Hilbert_basis = false;
1247
// Pyramid.do_deg1_elements=false;
1248
}
1249
1250
Pyramid.build_cone();
1251
1252
if(multithreaded_pyramid){
1253
#pragma omp atomic
1254
nrTotalComparisons+=Pyramid.nrTotalComparisons;
1255
} else
1256
nrTotalComparisons+=Pyramid.nrTotalComparisons;
1257
} // else non-simplicial
1258
}
1259
1260
1261
//---------------------------------------------------------------------------
1262
1263
template<typename Number>
1264
void Full_Cone<Number>::find_and_evaluate_start_simplex(){
1265
1266
size_t i,j;
1267
Number factor;
1268
1269
1270
/* Simplex<Number> S = find_start_simplex();
1271
vector<key_t> key=S.read_key(); // generators indexed from 0 */
1272
1273
vector<key_t> key=find_start_simplex();
1274
assert(key.size()==dim); // safety heck
1275
if(verbose){
1276
verboseOutput() << "Start simplex ";
1277
for(size_t i=0;i<key.size();++i)
1278
verboseOutput() << key[i]+1 << " ";
1279
verboseOutput() << endl;
1280
}
1281
Matrix<Number> H(dim,dim);
1282
Number vol;
1283
Generators.simplex_data(key,H,vol,do_partial_triangulation || do_triangulation);
1284
1285
// H.pretty_print(cout);
1286
1287
1288
for (i = 0; i < dim; i++) {
1289
in_triang[key[i]]=true;
1290
GensInCone.push_back(key[i]);
1291
if (deg1_triangulation && isComputed(ConeProperty::Grading))
1292
deg1_triangulation = (gen_degrees[key[i]] == 1);
1293
}
1294
1295
nrGensInCone=dim;
1296
1297
nrTotalComparisons=dim*dim/2;
1298
if(using_GMP<Number>())
1299
nrTotalComparisons*=GMP_time_factor/2; // because of the linear algebra involved in this routine
1300
Comparisons.push_back(nrTotalComparisons);
1301
1302
for (i = 0; i <dim; i++) {
1303
FACETDATA NewFacet; NewFacet.GenInHyp.resize(nr_gen);
1304
NewFacet.Hyp=H[i];
1305
NewFacet.simplicial=true; // indeed, the start simplex is simplicial
1306
for(j=0;j < dim;j++)
1307
if(j!=i)
1308
NewFacet.GenInHyp.set(key[j]);
1309
NewFacet.ValNewGen=-1; // must be taken negative since opposite facet
1310
number_hyperplane(NewFacet,0,0); // created with gen 0
1311
Facets.push_back(NewFacet); // was visible before adding this vertex
1312
}
1313
1314
if(!is_pyramid){
1315
//define Order_Vector, decides which facets of the simplices are excluded
1316
Order_Vector = vector<Number>(dim,0);
1317
// Matrix<Number> G=S.read_generators();
1318
for(i=0;i<dim;i++){
1319
factor=(unsigned long) (1+i%10); // (2*(rand()%(2*dim))+3);
1320
for(j=0;j<dim;j++)
1321
Order_Vector[j]+=factor*Generators[key[i]][j];
1322
}
1323
}
1324
1325
//the volume is an upper bound for the height
1326
if(do_triangulation || (do_partial_triangulation && vol>1))
1327
{
1328
store_key(key,vol,1,TriangulationBuffer);
1329
if(do_only_multiplicity) {
1330
#pragma omp atomic
1331
TotDet++;
1332
}
1333
} else if (do_partial_triangulation) {
1334
triangulation_is_partial = true;
1335
}
1336
1337
if(do_triangulation){ // we must prepare the sections of the triangulation
1338
for(i=0;i<dim;i++)
1339
{
1340
// GensInCone.push_back(key[i]); // now done in first loop since always needed
1341
TriSectionFirst.push_back(TriangulationBuffer.begin());
1342
TriSectionLast.push_back(TriangulationBuffer.begin());
1343
}
1344
}
1345
1346
}
1347
1348
1349
//---------------------------------------------------------------------------
1350
1351
template<typename Number>
1352
void Full_Cone<Number>::select_supphyps_from(const list<FACETDATA>& NewFacets,
1353
const size_t new_generator, const vector<key_t>& Pyramid_key){
1354
// the mother cone (=this) selects supphyps from the list NewFacets supplied by the daughter
1355
// the daughter provides the necessary information via the parameters
1356
1357
size_t i;
1358
boost::dynamic_bitset<> in_Pyr(nr_gen);
1359
for (i=0; i<Pyramid_key.size(); i++) {
1360
in_Pyr.set(Pyramid_key[i]);
1361
}
1362
// the new generator is always the first in the pyramid
1363
assert(Pyramid_key[0] == new_generator);
1364
1365
1366
typename list<FACETDATA>::const_iterator pyr_hyp = NewFacets.begin();
1367
bool new_global_hyp;
1368
FACETDATA NewFacet;
1369
NewFacet.GenInHyp.resize(nr_gen);
1370
Number test;
1371
for (; pyr_hyp!=NewFacets.end(); ++pyr_hyp) {
1372
if(!pyr_hyp->GenInHyp.test(0)) // new gen not in hyp
1373
continue;
1374
new_global_hyp=true;
1375
for (i=0; i<nr_gen; ++i){
1376
if(in_Pyr.test(i) || !in_triang[i])
1377
continue;
1378
test=v_scalar_product(Generators[i],pyr_hyp->Hyp);
1379
if(test<=0){
1380
new_global_hyp=false;
1381
break;
1382
}
1383
1384
}
1385
if(new_global_hyp){
1386
NewFacet.Hyp=pyr_hyp->Hyp;
1387
NewFacet.GenInHyp.reset();
1388
// size_t gens_in_facet=0;
1389
for (i=0; i<Pyramid_key.size(); ++i) {
1390
if (pyr_hyp->GenInHyp.test(i) && in_triang[Pyramid_key[i]]) {
1391
NewFacet.GenInHyp.set(Pyramid_key[i]);
1392
// gens_in_facet++;
1393
}
1394
}
1395
/* for (i=0; i<nr_gen; ++i) {
1396
if (NewFacet.GenInHyp.test(i) && in_triang[i]) {
1397
gens_in_facet++;
1398
}
1399
}*/
1400
// gens_in_facet++; // Note: new generator not yet in in_triang
1401
NewFacet.GenInHyp.set(new_generator);
1402
NewFacet.simplicial=pyr_hyp->simplicial; // (gens_in_facet==dim-1);
1403
check_simpliciality_hyperplane(NewFacet);
1404
number_hyperplane(NewFacet,nrGensInCone,0); //mother unknown
1405
if(multithreaded_pyramid){
1406
#pragma omp critical(GIVEBACKHYPS)
1407
Facets.push_back(NewFacet);
1408
} else {
1409
Facets.push_back(NewFacet);
1410
}
1411
}
1412
}
1413
}
1414
1415
//---------------------------------------------------------------------------
1416
template<typename Number>
1417
void Full_Cone<Number>::match_neg_hyp_with_pos_hyps(const FACETDATA& hyp, size_t new_generator,list<FACETDATA*>& PosHyps, boost::dynamic_bitset<>& Zero_P){
1418
1419
size_t missing_bound, nr_common_zero;
1420
boost::dynamic_bitset<> common_zero(nr_gen);
1421
vector<key_t> common_key;
1422
common_key.reserve(nr_gen);
1423
vector<key_t> key(nr_gen);
1424
bool common_subfacet;
1425
list<FACETDATA> NewHyp;
1426
size_t subfacet_dim=dim-2;
1427
size_t nr_missing;
1428
typename list<FACETDATA*>::iterator a;
1429
list<FACETDATA> NewHyps;
1430
Matrix<Number> Test(0,dim);
1431
1432
boost::dynamic_bitset<> zero_hyp=hyp.GenInHyp & Zero_P; // we intersect with the set of gens in positive hyps
1433
1434
size_t nr_zero_hyp=0;
1435
vector<int> key_start(nrGensInCone);
1436
size_t j;
1437
int last_existing=-1;
1438
for(size_t jj=0;jj<nrGensInCone;jj++)
1439
{
1440
j=GensInCone[jj];
1441
if(zero_hyp.test(j)){
1442
key[nr_zero_hyp]=j;
1443
for(size_t kk= last_existing+1;kk<=jj;kk++)
1444
key_start[kk]=nr_zero_hyp;
1445
nr_zero_hyp++;
1446
last_existing= jj;
1447
}
1448
}
1449
if(last_existing< (int)nrGensInCone-1)
1450
for(size_t kk=last_existing+1;kk<nrGensInCone;kk++)
1451
key_start[kk]=nr_zero_hyp;
1452
1453
if (nr_zero_hyp<dim-2)
1454
return;
1455
1456
int tn = omp_get_ancestor_thread_num(1);
1457
missing_bound=nr_zero_hyp-subfacet_dim; // at most this number of generators can be missing
1458
// to have a chance for common subfacet
1459
1460
typename list< FACETDATA*>::iterator hp_j_iterator=PosHyps.begin();
1461
1462
FACETDATA* hp_j;
1463
1464
for (;hp_j_iterator!=PosHyps.end();++hp_j_iterator){ //match hyp with the given Pos
1465
hp_j=*hp_j_iterator;
1466
1467
if(hyp.Ident==hp_j->Mother || hp_j->Ident==hyp.Mother){ // mother and daughter coming together
1468
// their intersection is a subfacet
1469
add_hyperplane(new_generator,*hp_j,hyp,NewHyps,false); // simplicial set in add_hyperplane
1470
continue;
1471
}
1472
1473
1474
bool extension_test=hyp.BornAt==hp_j->BornAt || (hyp.BornAt<hp_j->BornAt && hp_j->Mother!=0)
1475
|| (hp_j->BornAt<hyp.BornAt && hyp.Mother!=0);
1476
1477
size_t both_existing_from=key_start[max(hyp.BornAt,hp_j->BornAt)];
1478
1479
nr_missing=0;
1480
nr_common_zero=0;
1481
common_key.clear();
1482
size_t second_loop_bound=nr_zero_hyp;
1483
common_subfacet=true;
1484
boost::dynamic_bitset<> common_zero(nr_gen);
1485
1486
if(extension_test){
1487
bool extended=false;
1488
second_loop_bound=both_existing_from;
1489
for(size_t k=both_existing_from;k<nr_zero_hyp;k++){
1490
if(!hp_j->GenInHyp.test(key[k])) {
1491
nr_missing++;
1492
if(nr_missing>missing_bound) {
1493
common_subfacet=false;
1494
break;
1495
}
1496
}
1497
else {
1498
extended=true;
1499
common_key.push_back(key[k]);
1500
common_zero.set(key[k]);
1501
nr_common_zero++;
1502
}
1503
}
1504
1505
if(!extended || !common_subfacet) //
1506
continue;
1507
}
1508
1509
for(size_t k=0;k<second_loop_bound;k++) {
1510
if(!hp_j->GenInHyp.test(key[k])) {
1511
nr_missing++;
1512
if(nr_missing>missing_bound) {
1513
common_subfacet=false;
1514
break;
1515
}
1516
}
1517
else {
1518
common_key.push_back(key[k]);
1519
common_zero.set(key[k]);
1520
nr_common_zero++;
1521
}
1522
}
1523
1524
if(!common_subfacet)
1525
continue;
1526
1527
assert(nr_common_zero >=subfacet_dim);
1528
1529
1530
if (!hp_j->simplicial){
1531
1532
bool ranktest;
1533
/* if(using_GMP<Number>())
1534
ranktest = (old_nr_supp_hyps > 10*GMP_time_factor*dim*dim*nr_common_zero/3); // in this case the rank computation takes longer
1535
else
1536
ranktest = (old_nr_supp_hyps > 10*dim*dim*nr_common_zero/3); */
1537
1538
ranktest=true;
1539
1540
if(ranktest){
1541
// cout << "Rank" << endl;
1542
Matrix<Number>& Test = Top_Cone->RankTest[tn];
1543
if(Test.rank_submatrix(Generators,common_key)<subfacet_dim)
1544
common_subfacet=false; // don't make a hyperplane
1545
}
1546
else{ // now the comparison test
1547
// cout << "Compare" << endl;
1548
auto hp_t=Facets.begin();
1549
for (;hp_t!=Facets.end();++hp_t){
1550
if(hp_t->simplicial)
1551
continue;
1552
if ((hp_t->Ident!=hyp.Ident) && (hp_t->Ident!=hp_j->Ident) && common_zero.is_subset_of(hp_t->GenInHyp)) {
1553
common_subfacet=false;
1554
break;
1555
}
1556
}
1557
} // else
1558
} // !simplicial
1559
1560
if(common_subfacet)
1561
add_hyperplane(new_generator,*hp_j,hyp,NewHyps,false); // simplicial set in add_hyperplane
1562
} // for
1563
1564
if(multithreaded_pyramid)
1565
#pragma omp critical(GIVEBACKHYPS)
1566
Facets.splice(Facets.end(),NewHyps);
1567
else
1568
Facets.splice(Facets.end(),NewHyps);
1569
1570
}
1571
1572
//---------------------------------------------------------------------------
1573
template<typename Number>
1574
void Full_Cone<Number>::collect_pos_supphyps(list<FACETDATA*>& PosHyps, boost::dynamic_bitset<>& Zero_P, size_t& nr_pos){
1575
1576
// positive facets are collected in a list
1577
1578
typename list<FACETDATA>::iterator ii = Facets.begin();
1579
nr_pos=0;
1580
1581
for (size_t ij=0; ij< old_nr_supp_hyps; ++ij, ++ii)
1582
if (ii->ValNewGen>0) {
1583
Zero_P |= ii->GenInHyp;
1584
PosHyps.push_back(&(*ii));
1585
nr_pos++;
1586
}
1587
}
1588
1589
//---------------------------------------------------------------------------
1590
template<typename Number>
1591
void Full_Cone<Number>::evaluate_large_rec_pyramids(size_t new_generator){
1592
1593
size_t nrLargeRecPyrs=LargeRecPyrs.size();
1594
if(nrLargeRecPyrs==0)
1595
return;
1596
1597
if(verbose)
1598
verboseOutput() << "large pyramids " << nrLargeRecPyrs << endl;
1599
1600
list<FACETDATA*> PosHyps;
1601
boost::dynamic_bitset<> Zero_P(nr_gen);
1602
size_t nr_pos;
1603
collect_pos_supphyps(PosHyps,Zero_P,nr_pos);
1604
1605
nrTotalComparisons+=nr_pos*nrLargeRecPyrs;
1606
#ifndef NCATCH
1607
std::exception_ptr tmp_exception;
1608
#endif
1609
1610
const long VERBOSE_STEPS = 50;
1611
long step_x_size = nrLargeRecPyrs-VERBOSE_STEPS;
1612
const size_t RepBound=100;
1613
1614
#pragma omp parallel
1615
{
1616
size_t ppos=0;
1617
typename list<FACETDATA>::iterator p=LargeRecPyrs.begin();
1618
1619
#pragma omp for schedule(dynamic)
1620
for(size_t i=0; i<nrLargeRecPyrs; i++){
1621
for(; i > ppos; ++ppos, ++p) ;
1622
for(; i < ppos; --ppos, --p) {};
1623
1624
if(verbose && nrLargeRecPyrs>=RepBound){
1625
#pragma omp critical(VERBOSE)
1626
while ((long)(i*VERBOSE_STEPS) >= step_x_size) {
1627
step_x_size += nrLargeRecPyrs;
1628
verboseOutput() << "." <<flush;
1629
}
1630
}
1631
1632
#ifndef NCATCH
1633
try {
1634
#endif
1635
match_neg_hyp_with_pos_hyps(*p,new_generator,PosHyps,Zero_P);
1636
#ifndef NCATCH
1637
} catch(const std::exception& ) {
1638
tmp_exception = std::current_exception();
1639
}
1640
#endif
1641
}
1642
} // parallel
1643
#ifndef NCATCH
1644
if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);
1645
#endif
1646
1647
if(verbose && nrLargeRecPyrs>=RepBound)
1648
verboseOutput() << endl;
1649
1650
LargeRecPyrs.clear();
1651
}
1652
1653
//---------------------------------------------------------------------------
1654
1655
template<typename Number>
1656
bool Full_Cone<Number>::check_pyr_buffer(const size_t level){
1657
if(level==0)
1658
return(nrPyramids[0] > EvalBoundLevel0Pyr);
1659
else
1660
return(nrPyramids[level] > EvalBoundPyr);
1661
}
1662
1663
//---------------------------------------------------------------------------
1664
1665
template<typename Number>
1666
void Full_Cone<Number>::evaluate_stored_pyramids(const size_t level){
1667
// evaluates the stored non-recursive pyramids
1668
1669
assert(!omp_in_parallel());
1670
1671
if(Pyramids[level].empty())
1672
return;
1673
if (Pyramids.size() < level+2) {
1674
Pyramids.resize(level+2); // provide space for a new generation
1675
nrPyramids.resize(level+2, 0);
1676
}
1677
1678
size_t eval_down_to = 0;
1679
1680
#ifdef NMZ_MIC_OFFLOAD
1681
#ifndef __MIC__
1682
// only on host and if offload is available
1683
if (level == 0 && nrPyramids[0] > EvalBoundLevel0Pyr) {
1684
eval_down_to = EvalBoundLevel0Pyr;
1685
}
1686
#endif
1687
#endif
1688
1689
vector<char> Done(nrPyramids[level],0);
1690
if (verbose) {
1691
verboseOutput() << "**************************************************" << endl;
1692
1693
for (size_t l=0; l<=level; ++l) {
1694
if (nrPyramids[l]>0) {
1695
verboseOutput() << "level " << l << " pyramids remaining: "
1696
<< nrPyramids[l] << endl;
1697
}
1698
}
1699
verboseOutput() << "**************************************************" << endl;
1700
}
1701
typename list<vector<key_t> >::iterator p;
1702
size_t ppos;
1703
bool skip_remaining;
1704
#ifndef NCATCH
1705
std::exception_ptr tmp_exception;
1706
#endif
1707
1708
while (nrPyramids[level] > eval_down_to) {
1709
1710
p = Pyramids[level].begin();
1711
ppos=0;
1712
skip_remaining = false;
1713
1714
#pragma omp parallel for firstprivate(p,ppos) schedule(dynamic)
1715
for(size_t i=0; i<nrPyramids[level]; i++){
1716
if (skip_remaining)
1717
continue;
1718
for(; i > ppos; ++ppos, ++p) ;
1719
for(; i < ppos; --ppos, --p) ;
1720
1721
if(Done[i])
1722
continue;
1723
Done[i]=1;
1724
1725
#ifndef NCATCH
1726
try {
1727
#endif
1728
Full_Cone<Number> Pyramid(*this,*p);
1729
// Pyramid.recursion_allowed=false;
1730
Pyramid.do_all_hyperplanes=false;
1731
if (level>=2 && do_partial_triangulation){ // limits the descent of do_partial_triangulation
1732
Pyramid.do_triangulation=true;
1733
Pyramid.do_partial_triangulation=false;
1734
}
1735
Pyramid.store_level=level+1;
1736
Pyramid.build_cone();
1737
if (check_evaluation_buffer_size() || Top_Cone->check_pyr_buffer(level+1)) {
1738
// interrupt parallel execution to keep the buffer under control
1739
skip_remaining = true;
1740
}
1741
#ifndef NCATCH
1742
} catch(const std::exception& ) {
1743
tmp_exception = std::current_exception();
1744
skip_remaining = true;
1745
#pragma omp flush(skip_remaining)
1746
}
1747
#endif
1748
} //end parallel for
1749
#ifndef NCATCH
1750
if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);
1751
#endif
1752
1753
// remove done pyramids
1754
p = Pyramids[level].begin();
1755
for(size_t i=0; p != Pyramids[level].end(); i++){
1756
if (Done[i]) {
1757
p=Pyramids[level].erase(p);
1758
nrPyramids[level]--;
1759
Done[i]=0;
1760
} else {
1761
++p;
1762
}
1763
}
1764
1765
if (check_evaluation_buffer_size()) {
1766
if (verbose)
1767
verboseOutput() << nrPyramids[level] <<
1768
" pyramids remaining on level " << level << ", ";
1769
Top_Cone->evaluate_triangulation();
1770
}
1771
1772
if (Top_Cone->check_pyr_buffer(level+1)) {
1773
evaluate_stored_pyramids(level+1);
1774
}
1775
1776
} //end while (nrPyramids[level] > 0)
1777
1778
if (verbose) {
1779
verboseOutput() << "**************************************************" << endl;
1780
verboseOutput() << "all pyramids on level "<< level << " done!"<<endl;
1781
if (nrPyramids[level+1] == 0) {
1782
for (size_t l=0; l<=level; ++l) {
1783
if (nrPyramids[l]>0) {
1784
verboseOutput() << "level " << l << " pyramids remaining: "
1785
<< nrPyramids[l] << endl;
1786
}
1787
}
1788
verboseOutput() << "**************************************************" << endl;
1789
}
1790
}
1791
if(check_evaluation_buffer())
1792
{
1793
Top_Cone->evaluate_triangulation();
1794
}
1795
1796
evaluate_stored_pyramids(level+1);
1797
}
1798
1799
1800
1801
//---------------------------------------------------------------------------
1802
1803
/* builds the cone successively by inserting generators */
1804
template<typename Number>
1805
void Full_Cone<Number>::build_cone() {
1806
// if(dim>0){ //correction needed to include the 0 cone;
1807
1808
// cout << "Pyr " << pyr_level << endl;
1809
1810
long long RecBoundSuppHyp;
1811
RecBoundSuppHyp = dim*dim*dim*SuppHypRecursionFactor; //dim^3 * 50
1812
if(using_GMP<Number>())
1813
RecBoundSuppHyp*=GMP_time_factor; // pyramid building is more difficult for complicated arithmetic
1814
1815
size_t RecBoundTriang=1000000; // if number(supphyps)*size(triang) > RecBoundTriang pass to pyramids
1816
if(using_GMP<Number>())
1817
RecBoundTriang*=GMP_time_factor;
1818
1819
tri_recursion=false;
1820
1821
multithreaded_pyramid=(omp_get_level()==0);
1822
1823
if(!use_existing_facets){
1824
if(multithreaded_pyramid){
1825
HypCounter.resize(omp_get_max_threads());
1826
for(size_t i=0;i<HypCounter.size();++i)
1827
HypCounter[i]=i+1;
1828
} else{
1829
HypCounter.resize(1);
1830
HypCounter[0]=1;
1831
}
1832
1833
find_and_evaluate_start_simplex();
1834
}
1835
1836
size_t last_to_be_inserted; // good to know in case of do_all_hyperplanes==false
1837
last_to_be_inserted=nr_gen-1; // because we don't need to compute support hyperplanes in this case
1838
for(int j=nr_gen-1;j>=0;--j){
1839
if(!in_triang[j]){
1840
last_to_be_inserted=j;
1841
break;
1842
}
1843
} // last_to_be_inserted now determined
1844
1845
bool is_new_generator;
1846
typename list< FACETDATA >::iterator l;
1847
1848
1849
for (size_t i=start_from;i<nr_gen;++i) {
1850
1851
start_from=i;
1852
1853
if (in_triang[i])
1854
continue;
1855
1856
if(do_triangulation && TriangulationBufferSize > 2*RecBoundTriang) // emermergency brake
1857
tri_recursion=true; // to switch off production of simplices in favor
1858
// of non-recursive pyramids
1859
Number scalar_product;
1860
is_new_generator=false;
1861
l=Facets.begin();
1862
old_nr_supp_hyps=Facets.size(); // Facets will be xtended in the loop
1863
1864
long long nr_pos=0, nr_neg=0;
1865
long long nr_neg_simp=0, nr_pos_simp=0;
1866
vector<Number> L;
1867
#ifndef NCATCH
1868
std::exception_ptr tmp_exception;
1869
#endif
1870
1871
size_t lpos=0;
1872
#pragma omp parallel for private(L,scalar_product) firstprivate(lpos,l) reduction(+: nr_pos, nr_neg)
1873
for (size_t k=0; k<old_nr_supp_hyps; k++) {
1874
#ifndef NCATCH
1875
try {
1876
#endif
1877
for(;k > lpos; lpos++, l++) ;
1878
for(;k < lpos; lpos--, l--) ;
1879
1880
L=Generators[i];
1881
scalar_product=v_scalar_product(L,(*l).Hyp);
1882
l->ValNewGen=scalar_product;
1883
if (scalar_product<0) {
1884
is_new_generator=true;
1885
nr_neg++;
1886
if(l->simplicial)
1887
#pragma omp atomic
1888
nr_neg_simp++;
1889
}
1890
if (scalar_product>0) {
1891
nr_pos++;
1892
if(l->simplicial)
1893
#pragma omp atomic
1894
nr_pos_simp++;
1895
}
1896
#ifndef NCATCH
1897
} catch(const std::exception& ) {
1898
tmp_exception = std::current_exception();
1899
}
1900
#endif
1901
} //end parallel for
1902
#ifndef NCATCH
1903
if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);
1904
#endif
1905
1906
if(!is_new_generator)
1907
continue;
1908
1909
// the i-th generator is used in the triangulation
1910
// in_triang[i]=true; // now at end of loop
1911
if (deg1_triangulation && isComputed(ConeProperty::Grading))
1912
deg1_triangulation = (gen_degrees[i] == 1);
1913
1914
/* if(!is_pyramid && verbose )
1915
verboseOutput() << "Neg " << nr_neg << " Pos " << nr_pos << " NegSimp " <<nr_neg_simp << " PosSimp " <<nr_pos_simp << endl;*/
1916
// First we test whether to go to recursive pyramids because of too many supphyps
1917
// cout << "GMP " << using_GMP<Number>() << " Bound " << RecBoundSuppHyp << " " << nr_neg*nr_pos-(nr_neg_simp*nr_pos_simp) << endl;
1918
if (recursion_allowed && nr_neg*nr_pos-(nr_neg_simp*nr_pos_simp) > RecBoundSuppHyp) { // use pyramids because of supphyps
1919
/* if(!is_pyramid && verbose )
1920
verboseOutput() << "Building pyramids" << endl; */
1921
if (do_triangulation)
1922
tri_recursion = true; // We can not go back to classical triangulation
1923
if(check_evaluation_buffer()){
1924
Top_Cone->evaluate_triangulation();
1925
}
1926
1927
process_pyramids(i,true); //recursive
1928
lastGen=i;
1929
nextGen=i+1;
1930
}
1931
else{ // now we check whether to go to pyramids because of the size of triangulation
1932
// once we have done so, we must stay with it
1933
if( tri_recursion || (do_triangulation
1934
&& (nr_neg*TriangulationBufferSize > RecBoundTriang
1935
|| 3*omp_get_max_threads()*TriangulationBufferSize>EvalBoundTriang ))){ // go to pyramids because of triangulation
1936
if(check_evaluation_buffer()){
1937
Top_Cone->evaluate_triangulation();
1938
}
1939
tri_recursion=true;
1940
process_pyramids(i,false); //non-recursive
1941
}
1942
else{ // no pyramids necesary
1943
if(do_partial_triangulation)
1944
process_pyramids(i,false); // non-recursive
1945
if(do_triangulation)
1946
extend_triangulation(i);
1947
}
1948
1949
if(do_all_hyperplanes || i!=last_to_be_inserted)
1950
find_new_facets(i);
1951
}
1952
1953
// removing the negative hyperplanes if necessary
1954
if(do_all_hyperplanes || i!=last_to_be_inserted){
1955
l=Facets.begin();
1956
for (size_t j=0; j<old_nr_supp_hyps;j++){
1957
if (l->ValNewGen<0) {
1958
l=Facets.erase(l);
1959
}
1960
else
1961
++l;
1962
}
1963
}
1964
1965
GensInCone.push_back(i);
1966
nrGensInCone++;
1967
1968
Comparisons.push_back(nrTotalComparisons);
1969
1970
if(verbose) {
1971
verboseOutput() << "gen="<< i+1 <<", ";
1972
if (do_all_hyperplanes || i!=last_to_be_inserted) {
1973
verboseOutput() << Facets.size()<<" hyp";
1974
} else {
1975
verboseOutput() << Support_Hyperplanes.nr_of_rows()<<" hyp";
1976
}
1977
if(nrPyramids[0]>0)
1978
verboseOutput() << ", " << nrPyramids[0] << " pyr";
1979
if(do_triangulation||do_partial_triangulation)
1980
verboseOutput() << ", " << TriangulationBufferSize << " simpl";
1981
verboseOutput()<< endl;
1982
}
1983
1984
in_triang[i]=true;
1985
1986
} // loop over i
1987
1988
start_from=nr_gen;
1989
1990
if (is_pyramid && do_all_hyperplanes) // must give supphyps back to mother
1991
Mother->select_supphyps_from(Facets, apex, Mother_Key);
1992
1993
// transfer Facets --> SupportHyperplanes
1994
if (do_all_hyperplanes) {
1995
nrSupport_Hyperplanes = Facets.size();
1996
Support_Hyperplanes = Matrix<Number>(nrSupport_Hyperplanes,0);
1997
typename list<FACETDATA>::iterator IHV=Facets.begin();
1998
for (size_t i=0; i<nrSupport_Hyperplanes; ++i, ++IHV) {
1999
swap(Support_Hyperplanes[i],IHV->Hyp);
2000
}
2001
is_Computed.set(ConeProperty::SupportHyperplanes);
2002
}
2003
Support_Hyperplanes.set_nr_of_columns(dim);
2004
2005
2006
if(do_extreme_rays && do_all_hyperplanes)
2007
compute_extreme_rays(true);
2008
2009
transfer_triangulation_to_top(); // transfer remaining simplices to top
2010
if(check_evaluation_buffer()){
2011
Top_Cone->evaluate_triangulation();
2012
}
2013
2014
// } // end if (dim>0)
2015
2016
Facets.clear();
2017
2018
}
2019
2020
template<typename Number>
2021
void Full_Cone<Number>::start_message() {
2022
2023
if (verbose) {
2024
verboseOutput()<<"************************************************************"<<endl;
2025
verboseOutput()<<"starting primal algorithm ";
2026
if (do_partial_triangulation) verboseOutput()<<"with partial triangulation ";
2027
if (do_triangulation) {
2028
verboseOutput()<<"with full triangulation ";
2029
}
2030
if (!do_triangulation && !do_partial_triangulation) verboseOutput()<<"(only support hyperplanes) ";
2031
verboseOutput()<<"..."<<endl;
2032
}
2033
}
2034
2035
template<typename Number>
2036
void Full_Cone<Number>::end_message() {
2037
2038
if (verbose) {
2039
verboseOutput() << "------------------------------------------------------------"<<endl;
2040
}
2041
}
2042
2043
2044
//---------------------------------------------------------------------------
2045
2046
template<typename Number>
2047
void Full_Cone<Number>::build_top_cone() {
2048
2049
if(dim==0)
2050
return;
2051
2052
// if( ( !do_bottom_dec || deg1_generated || dim==1 || (!do_triangulation && !do_partial_triangulation))) {
2053
build_cone();
2054
// }
2055
2056
evaluate_stored_pyramids(0); // force evaluation of remaining pyramids
2057
}
2058
2059
//---------------------------------------------------------------------------
2060
2061
template<typename Number>
2062
bool Full_Cone<Number>::check_evaluation_buffer(){
2063
2064
return(omp_get_level()==0 && check_evaluation_buffer_size());
2065
}
2066
2067
//---------------------------------------------------------------------------
2068
2069
template<typename Number>
2070
bool Full_Cone<Number>::check_evaluation_buffer_size(){
2071
2072
return(!Top_Cone->keep_triangulation &&
2073
Top_Cone->TriangulationBufferSize > EvalBoundTriang);
2074
}
2075
2076
//---------------------------------------------------------------------------
2077
2078
template<typename Number>
2079
void Full_Cone<Number>::transfer_triangulation_to_top(){ // NEW EVA
2080
2081
size_t i;
2082
2083
// cout << "Pyr level " << pyr_level << endl;
2084
2085
if(!is_pyramid) { // we are in top cone
2086
if(check_evaluation_buffer()){
2087
evaluate_triangulation();
2088
}
2089
return; // no transfer necessary
2090
}
2091
2092
// now we are in a pyramid
2093
2094
// cout << "In pyramid " << endl;
2095
int tn = 0;
2096
if (omp_in_parallel())
2097
tn = omp_get_ancestor_thread_num(1);
2098
2099
typename list< SHORTSIMPLEX<Number> >::iterator pyr_simp=TriangulationBuffer.begin();
2100
while (pyr_simp!=TriangulationBuffer.end()) {
2101
if (pyr_simp->height == 0) { // it was marked to be skipped
2102
Top_Cone->FS[tn].splice(Top_Cone->FS[tn].end(), TriangulationBuffer, pyr_simp++);
2103
--TriangulationBufferSize;
2104
} else {
2105
for (i=0; i<dim; i++) // adjust key to topcone generators
2106
pyr_simp->key[i]=Top_Key[pyr_simp->key[i]];
2107
++pyr_simp;
2108
}
2109
}
2110
2111
// cout << "Keys transferred " << endl;
2112
#pragma omp critical(TRIANG)
2113
{
2114
Top_Cone->TriangulationBuffer.splice(Top_Cone->TriangulationBuffer.end(),TriangulationBuffer);
2115
Top_Cone->TriangulationBufferSize += TriangulationBufferSize;
2116
}
2117
TriangulationBufferSize = 0;
2118
2119
}
2120
2121
//---------------------------------------------------------------------------
2122
template<typename Number>
2123
void Full_Cone<Number>::get_supphyps_from_copy(bool from_scratch){
2124
2125
if(isComputed(ConeProperty::SupportHyperplanes)) // we have them already
2126
return;
2127
2128
Full_Cone copy((*this).Generators);
2129
copy.verbose=verbose;
2130
if(!from_scratch){
2131
copy.start_from=start_from;
2132
copy.use_existing_facets=true;
2133
copy.keep_order=true;
2134
copy.HypCounter=HypCounter;
2135
copy.Extreme_Rays_Ind=Extreme_Rays_Ind;
2136
copy.in_triang=in_triang;
2137
copy.old_nr_supp_hyps=old_nr_supp_hyps;
2138
if(isComputed(ConeProperty::ExtremeRays))
2139
copy.is_Computed.set(ConeProperty::ExtremeRays);
2140
copy.GensInCone=GensInCone;
2141
copy.nrGensInCone=nrGensInCone;
2142
copy.Comparisons=Comparisons;
2143
if(!Comparisons.empty())
2144
copy.nrTotalComparisons=Comparisons[Comparisons.size()-1];
2145
2146
typename list< FACETDATA >::const_iterator l=Facets.begin();
2147
2148
for(size_t i=0;i<old_nr_supp_hyps;++i){
2149
copy.Facets.push_back(*l);
2150
++l;
2151
}
2152
}
2153
2154
copy.dualize_cone();
2155
2156
std::swap(Support_Hyperplanes,copy.Support_Hyperplanes);
2157
nrSupport_Hyperplanes = copy.nrSupport_Hyperplanes;
2158
is_Computed.set(ConeProperty::SupportHyperplanes);
2159
do_all_hyperplanes = false;
2160
}
2161
2162
//---------------------------------------------------------------------------
2163
2164
template<typename Number>
2165
void Full_Cone<Number>::evaluate_triangulation(){
2166
2167
assert(omp_get_level()==0);
2168
2169
if (TriangulationBufferSize == 0)
2170
return;
2171
2172
if (keep_triangulation) {
2173
Triangulation.splice(Triangulation.end(),TriangulationBuffer);
2174
} else {
2175
// #pragma omp critical(FREESIMPL)
2176
FreeSimpl.splice(FreeSimpl.begin(),TriangulationBuffer);
2177
}
2178
TriangulationBufferSize=0;
2179
2180
}
2181
2182
//---------------------------------------------------------------------------
2183
2184
template<typename Number>
2185
void Full_Cone<Number>::primal_algorithm(){
2186
2187
primal_algorithm_initialize();
2188
2189
/***** Main Work is done in build_top_cone() *****/
2190
build_top_cone(); // evaluates if keep_triangulation==false
2191
/***** Main Work is done in build_top_cone() *****/
2192
2193
check_pointed();
2194
if(!pointed){
2195
throw NonpointedException();
2196
}
2197
2198
primal_algorithm_finalize();
2199
primal_algorithm_set_computed();
2200
}
2201
2202
//---------------------------------------------------------------------------
2203
2204
template<typename Number>
2205
void Full_Cone<Number>::primal_algorithm_initialize() {
2206
2207
}
2208
2209
//---------------------------------------------------------------------------
2210
2211
template<typename Number>
2212
void Full_Cone<Number>::primal_algorithm_finalize() {
2213
2214
evaluate_triangulation();
2215
2216
if (keep_triangulation) {
2217
is_Computed.set(ConeProperty::Triangulation);
2218
totalNrSimplices=0;
2219
auto t=Triangulation.begin();
2220
detSum=0;
2221
for(;t!=Triangulation.end();++t){
2222
totalNrSimplices++;
2223
t->vol=Generators.submatrix(t->key).vol();
2224
detSum+=t->vol;
2225
}
2226
is_Computed.set(ConeProperty::TriangulationDetSum);
2227
is_Computed.set(ConeProperty::TriangulationSize);
2228
}
2229
2230
if (do_cone_dec) {
2231
is_Computed.set(ConeProperty::ConeDecomposition);
2232
}
2233
2234
FreeSimpl.clear();
2235
2236
if(verbose) {
2237
verboseOutput() << "Total number of pyramids = "<< totalNrPyr << ", among them simplicial " << nrSimplicialPyr << endl;
2238
// cout << "Uni "<< Unimod << " Ht1NonUni " << Ht1NonUni << " NonDecided " << NonDecided << " TotNonDec " << NonDecidedHyp<< endl;
2239
}
2240
2241
}
2242
2243
2244
//---------------------------------------------------------------------------
2245
2246
template<typename Number>
2247
void Full_Cone<Number>::primal_algorithm_set_computed() {
2248
2249
extreme_rays_and_deg1_check();
2250
if(!pointed){
2251
throw NonpointedException();
2252
}
2253
2254
if (do_triangulation || do_partial_triangulation) {
2255
is_Computed.set(ConeProperty::TriangulationSize,true);
2256
if (do_evaluation) {
2257
is_Computed.set(ConeProperty::TriangulationDetSum,true);
2258
}
2259
}
2260
}
2261
2262
2263
//---------------------------------------------------------------------------
2264
// Normaliz modes (public)
2265
//---------------------------------------------------------------------------
2266
2267
// check the do_* bools, they must be set in advance
2268
// this method (de)activate them according to dependencies between them
2269
template<typename Number>
2270
void Full_Cone<Number>::do_vars_check(bool with_default) {
2271
2272
do_extreme_rays=true; // we always want to do this if compute() is called
2273
2274
/* if (do_default_mode && with_default) {
2275
do_Hilbert_basis = true;
2276
do_h_vector = true;
2277
if(!inhomogeneous)
2278
do_class_group=true;
2279
}
2280
*/
2281
2282
if (do_integrally_closed) {
2283
if (do_Hilbert_basis) {
2284
do_integrally_closed = false; // don't interrupt the computation
2285
} else {
2286
do_Hilbert_basis = true;
2287
}
2288
}
2289
2290
// activate implications
2291
if (do_module_gens_intcl) do_Hilbert_basis= true;
2292
if (do_module_gens_intcl) use_bottom_points= false;
2293
//if (do_hsop) do_Hilbert_basis = true;
2294
if (do_Stanley_dec) keep_triangulation = true;
2295
if (do_cone_dec) keep_triangulation = true;
2296
if (keep_triangulation) do_determinants = true;
2297
if (do_multiplicity) do_determinants = true;
2298
if ((do_multiplicity || do_h_vector) && inhomogeneous) do_module_rank = true;
2299
if (do_determinants) do_triangulation = true;
2300
if (do_h_vector && (with_default || explicit_h_vector)) do_triangulation = true;
2301
if (do_deg1_elements) do_partial_triangulation = true;
2302
if (do_Hilbert_basis) do_partial_triangulation = true;
2303
// activate
2304
do_only_multiplicity = do_determinants;
2305
stop_after_cone_dec = true;
2306
if(do_cone_dec) do_only_multiplicity=false;
2307
2308
if (do_Stanley_dec || do_h_vector || do_deg1_elements
2309
|| do_Hilbert_basis) {
2310
do_only_multiplicity = false;
2311
stop_after_cone_dec = false;
2312
do_evaluation = true;
2313
}
2314
if (do_determinants) do_evaluation = true;
2315
2316
// deactivate
2317
if (do_triangulation) do_partial_triangulation = false;
2318
if (do_Hilbert_basis) do_deg1_elements = false; // they will be extracted later
2319
}
2320
2321
2322
// general purpose compute method
2323
// do_* bools must be set in advance, this method does sanity checks for it
2324
// if no bool is set it does support hyperplanes and extreme rays
2325
template<typename Number>
2326
void Full_Cone<Number>::compute() {
2327
2328
if(dim==0){
2329
set_zero_cone();
2330
return;
2331
}
2332
2333
2334
do_vars_check(false);
2335
explicit_full_triang=do_triangulation; // to distinguish it from do_triangulation via default mode
2336
if(do_default_mode)
2337
do_vars_check(true);
2338
2339
start_message();
2340
2341
if(Support_Hyperplanes.nr_of_rows()==0 && !do_Hilbert_basis && !do_h_vector && !do_multiplicity && !do_deg1_elements
2342
&& !do_Stanley_dec && !do_triangulation && !do_determinants)
2343
assert(Generators.max_rank_submatrix_lex().size() == dim);
2344
2345
minimize_support_hyperplanes(); // if they are given
2346
if (inhomogeneous)
2347
set_levels();
2348
2349
if ((!do_triangulation && !do_partial_triangulation)
2350
|| (Grading.size()>0 && !isComputed(ConeProperty::Grading))){
2351
// in the second case there are only two possibilities:
2352
// either nonpointed or bad grading
2353
do_triangulation=false;
2354
do_partial_triangulation=false;
2355
support_hyperplanes();
2356
}
2357
else{
2358
if(isComputed(ConeProperty::IsPointed) && !pointed){
2359
end_message();
2360
return;
2361
}
2362
2363
sort_gens_by_degree(true);
2364
2365
primal_algorithm();
2366
}
2367
2368
end_message();
2369
}
2370
2371
2372
2373
2374
// -s
2375
template<typename Number>
2376
void Full_Cone<Number>::support_hyperplanes() {
2377
if(!isComputed(ConeProperty::SupportHyperplanes)){
2378
sort_gens_by_degree(false); // we do not want to triangulate here
2379
build_top_cone();
2380
}
2381
extreme_rays_and_deg1_check();
2382
if(inhomogeneous){
2383
find_level0_dim();
2384
}
2385
}
2386
2387
//---------------------------------------------------------------------------
2388
// Checks and auxiliary algorithms
2389
//---------------------------------------------------------------------------
2390
2391
template<typename Number>
2392
void Full_Cone<Number>::extreme_rays_and_deg1_check() {
2393
check_pointed();
2394
if(!pointed){
2395
throw NonpointedException();
2396
}
2397
//cout << "Generators" << endl;
2398
//Generators.pretty_print(cout);
2399
//cout << "SupportHyperplanes" << endl;
2400
//Support_Hyperplanes.pretty_print(cout);
2401
compute_extreme_rays();
2402
}
2403
2404
//---------------------------------------------------------------------------
2405
2406
template<typename Number>
2407
void Full_Cone<Number>::find_level0_dim(){
2408
2409
if(!isComputed(ConeProperty::Generators)){
2410
throw FatalException("Missing Generators.");
2411
}
2412
2413
Matrix<Number> Help(nr_gen,dim);
2414
for(size_t i=0; i<nr_gen;++i)
2415
if(gen_levels[i]==0)
2416
Help[i]=Generators[i];
2417
2418
ProjToLevel0Quot=Help.kernel();
2419
2420
level0_dim=dim-ProjToLevel0Quot.nr_of_rows();
2421
is_Computed.set(ConeProperty::RecessionRank);
2422
}
2423
2424
//---------------------------------------------------------------------------
2425
2426
template<typename Number>
2427
void Full_Cone<Number>::set_levels() {
2428
if(inhomogeneous && Truncation.size()!=dim){
2429
throw FatalException("Truncation not defined in inhomogeneous case.");
2430
}
2431
2432
// cout <<"trunc " << Truncation;
2433
2434
if(gen_levels.size()!=nr_gen) // now we compute the levels
2435
{
2436
gen_levels.resize(nr_gen);
2437
vector<Number> gen_levels_Number=Generators.MxV(Truncation);
2438
for (size_t i=0; i<nr_gen; i++) {
2439
if (gen_levels_Number[i] < 0) {
2440
throw FatalException("Truncation gives non-positive value "
2441
+ toString(gen_levels_Number[i]) + " for generator "
2442
+ toString(i+1) + ".");
2443
}
2444
convert(gen_levels[i], gen_levels_Number[i]);
2445
// cout << "Gen " << Generators[i];
2446
// cout << "level " << gen_levels[i] << endl << "----------------------" << endl;
2447
}
2448
}
2449
2450
}
2451
2452
//---------------------------------------------------------------------------
2453
2454
template<typename Number>
2455
void Full_Cone<Number>::sort_gens_by_degree(bool triangulate) {
2456
// if(deg1_extreme_rays) // gen_degrees.size()==0 ||
2457
// return;
2458
2459
if(keep_order)
2460
return;
2461
2462
Matrix<Number> Weights(0,dim);
2463
vector<bool> absolute;
2464
if(triangulate){
2465
Weights.append(vector<Number>(dim,1));
2466
absolute.push_back(true);
2467
}
2468
2469
vector<key_t> perm=Generators.perm_by_weights(Weights,absolute);
2470
Generators.order_rows_by_perm(perm);
2471
order_by_perm(Extreme_Rays_Ind,perm);
2472
if(inhomogeneous && gen_levels.size()==nr_gen)
2473
order_by_perm(gen_levels,perm);
2474
compose_perm_gens(perm);
2475
2476
if (verbose) {
2477
if(triangulate){
2478
if(isComputed(ConeProperty::Grading)){
2479
verboseOutput() <<"Generators sorted by degree and lexicographically" << endl;
2480
verboseOutput() << "Generators per degree:" << endl;
2481
verboseOutput() << count_in_map<long,long>(gen_degrees);
2482
}
2483
else
2484
verboseOutput() << "Generators sorted by 1-norm and lexicographically" << endl;
2485
}
2486
else{
2487
verboseOutput() << "Generators sorted lexicographically" << endl;
2488
}
2489
}
2490
keep_order=true;
2491
}
2492
2493
//---------------------------------------------------------------------------
2494
2495
template<typename Number>
2496
void Full_Cone<Number>::compose_perm_gens(const vector<key_t>& perm) {
2497
order_by_perm(PermGens,perm);
2498
}
2499
2500
//---------------------------------------------------------------------------
2501
2502
// an alternative to compute() for the basic tasks that need no triangulation
2503
template<typename Number>
2504
void Full_Cone<Number>::dualize_cone(bool print_message){
2505
2506
if(dim==0){
2507
set_zero_cone();
2508
return;
2509
}
2510
2511
// DO NOT CALL do_vars_check!!
2512
2513
bool save_tri = do_triangulation;
2514
bool save_part_tri = do_partial_triangulation;
2515
do_triangulation = false;
2516
do_partial_triangulation = false;
2517
2518
if(print_message) start_message();
2519
2520
sort_gens_by_degree(false);
2521
2522
if(!isComputed(ConeProperty::SupportHyperplanes))
2523
build_top_cone();
2524
2525
if(do_pointed)
2526
check_pointed();
2527
2528
if(do_extreme_rays) // in case we have known the support hyperplanes
2529
compute_extreme_rays();
2530
2531
do_triangulation = save_tri;
2532
do_partial_triangulation = save_part_tri;
2533
if(print_message) end_message();
2534
}
2535
2536
//---------------------------------------------------------------------------
2537
2538
template<typename Number>
2539
vector<key_t> Full_Cone<Number>::find_start_simplex() const {
2540
return Generators.max_rank_submatrix_lex();
2541
}
2542
2543
//---------------------------------------------------------------------------
2544
2545
template<typename Number>
2546
Matrix<Number> Full_Cone<Number>::select_matrix_from_list(const list<vector<Number> >& S,
2547
vector<size_t>& selection){
2548
2549
sort(selection.begin(),selection.end());
2550
assert(selection.back()<S.size());
2551
size_t i=0,j=0;
2552
size_t k=selection.size();
2553
Matrix<Number> M(selection.size(),S.front().size());
2554
typename list<vector<Number> >::const_iterator ll=S.begin();
2555
for(;ll!=S.end()&&i<k;++ll){
2556
if(j==selection[i]){
2557
M[i]=*ll;
2558
i++;
2559
}
2560
j++;
2561
}
2562
return M;
2563
}
2564
2565
//---------------------------------------------------------------------------
2566
2567
template<typename Number>
2568
2569
void Full_Cone<Number>::minimize_support_hyperplanes(){
2570
if(Support_Hyperplanes.nr_of_rows() == 0)
2571
return;
2572
if(isComputed(ConeProperty::SupportHyperplanes)){
2573
nrSupport_Hyperplanes=Support_Hyperplanes.nr_of_rows();
2574
return;
2575
}
2576
if (verbose) {
2577
verboseOutput() << "Minimize the given set of support hyperplanes by "
2578
<< "computing the extreme rays of the dual cone" << endl;
2579
}
2580
Full_Cone<Number> Dual(Support_Hyperplanes);
2581
Dual.verbose=verbose;
2582
Dual.Support_Hyperplanes = Generators;
2583
Dual.is_Computed.set(ConeProperty::SupportHyperplanes);
2584
Dual.compute_extreme_rays();
2585
Support_Hyperplanes = Dual.Generators.submatrix(Dual.Extreme_Rays_Ind); //only essential hyperplanes
2586
is_Computed.set(ConeProperty::SupportHyperplanes);
2587
nrSupport_Hyperplanes=Support_Hyperplanes.nr_of_rows();
2588
do_all_hyperplanes=false;
2589
}
2590
2591
2592
//---------------------------------------------------------------------------
2593
2594
template<typename Number>
2595
void Full_Cone<Number>::compute_extreme_rays(bool use_facets){
2596
2597
if (isComputed(ConeProperty::ExtremeRays))
2598
return;
2599
// when we do approximation, we do not have the correct hyperplanes
2600
// and cannot compute the extreme rays
2601
if (is_approximation)
2602
return;
2603
assert(isComputed(ConeProperty::SupportHyperplanes));
2604
2605
check_pointed();
2606
if(!pointed){
2607
throw NonpointedException();
2608
}
2609
2610
if(dim*Support_Hyperplanes.nr_of_rows() < nr_gen) {
2611
compute_extreme_rays_rank(use_facets);
2612
} else {
2613
compute_extreme_rays_compare(use_facets);
2614
}
2615
}
2616
2617
//---------------------------------------------------------------------------
2618
2619
template<typename Number>
2620
void Full_Cone<Number>::compute_extreme_rays_rank(bool use_facets){
2621
2622
if (verbose) verboseOutput() << "Select extreme rays via rank ... " << flush;
2623
2624
size_t i;
2625
vector<key_t> gen_in_hyperplanes;
2626
gen_in_hyperplanes.reserve(Support_Hyperplanes.nr_of_rows());
2627
Matrix<Number> M(Support_Hyperplanes.nr_of_rows(),dim);
2628
2629
deque<bool> Ext(nr_gen,false);
2630
#pragma omp parallel for firstprivate(gen_in_hyperplanes,M)
2631
for(i=0;i<nr_gen;++i){
2632
// if (isComputed(ConeProperty::Triangulation) && !in_triang[i])
2633
// continue;
2634
gen_in_hyperplanes.clear();
2635
if(use_facets){
2636
typename list<FACETDATA>::const_iterator IHV=Facets.begin();
2637
for (size_t j=0; j<Support_Hyperplanes.nr_of_rows(); ++j, ++IHV){
2638
if(IHV->GenInHyp.test(i))
2639
gen_in_hyperplanes.push_back(j);
2640
}
2641
}
2642
else{
2643
for (size_t j=0; j<Support_Hyperplanes.nr_of_rows(); ++j){
2644
if(v_scalar_product(Generators[i],Support_Hyperplanes[j])==0)
2645
gen_in_hyperplanes.push_back(j);
2646
}
2647
}
2648
if (gen_in_hyperplanes.size() < dim-1)
2649
continue;
2650
if (M.rank_submatrix(Support_Hyperplanes,gen_in_hyperplanes) >= dim-1)
2651
Ext[i]=true;
2652
}
2653
for(i=0; i<nr_gen;++i)
2654
Extreme_Rays_Ind[i]=Ext[i];
2655
2656
is_Computed.set(ConeProperty::ExtremeRays);
2657
if (verbose) verboseOutput() << "done." << endl;
2658
}
2659
2660
//---------------------------------------------------------------------------
2661
2662
template<typename Number>
2663
void Full_Cone<Number>::compute_extreme_rays_compare(bool use_facets){
2664
2665
if (verbose) verboseOutput() << "Select extreme rays via comparison ... " << flush;
2666
2667
size_t i,j,k;
2668
// Matrix<Number> SH=getSupportHyperplanes().transpose();
2669
// Matrix<Number> Val=Generators.multiplication(SH);
2670
size_t nc=Support_Hyperplanes.nr_of_rows();
2671
2672
vector<vector<bool> > Val(nr_gen);
2673
for (i=0;i<nr_gen;++i)
2674
Val[i].resize(nc);
2675
2676
// In this routine Val[i][j]==1, i.e. true, indicates that
2677
// the i-th generator is contained in the j-th support hyperplane
2678
2679
vector<key_t> Zero(nc);
2680
vector<key_t> nr_ones(nr_gen);
2681
2682
for (i = 0; i <nr_gen; i++) {
2683
k=0;
2684
Extreme_Rays_Ind[i]=true;
2685
if(use_facets){
2686
typename list<FACETDATA>::const_iterator IHV=Facets.begin();
2687
for (j=0; j<Support_Hyperplanes.nr_of_rows(); ++j, ++IHV){
2688
if(IHV->GenInHyp.test(i)){
2689
k++;
2690
Val[i][j]=true;
2691
}
2692
else
2693
Val[i][j]=false;
2694
}
2695
}
2696
else{
2697
for (j = 0; j <nc; ++j) {
2698
if (v_scalar_product(Generators[i],Support_Hyperplanes[j])==0) {
2699
k++;
2700
Val[i][j]=true;
2701
}
2702
else
2703
Val[i][j]=false;
2704
}
2705
}
2706
nr_ones[i]=k;
2707
if (k<dim-1||k==nc) // not contained in enough facets or in all (0 as generator)
2708
Extreme_Rays_Ind[i]=false;
2709
}
2710
2711
maximal_subsets(Val,Extreme_Rays_Ind);
2712
2713
is_Computed.set(ConeProperty::ExtremeRays);
2714
if (verbose) verboseOutput() << "done." << endl;
2715
}
2716
2717
//---------------------------------------------------------------------------
2718
2719
template<typename Number>
2720
bool Full_Cone<Number>::contains(const vector<Number>& v) {
2721
for (size_t i=0; i<Support_Hyperplanes.nr_of_rows(); ++i)
2722
if (v_scalar_product(Support_Hyperplanes[i],v) < 0)
2723
return false;
2724
return true;
2725
}
2726
//---------------------------------------------------------------------------
2727
2728
template<typename Number>
2729
bool Full_Cone<Number>::contains(const Full_Cone& C) {
2730
for(size_t i=0;i<C.nr_gen;++i)
2731
if(!contains(C.Generators[i])){
2732
cerr << "Missing generator " << C.Generators[i] << endl;
2733
return(false);
2734
}
2735
return(true);
2736
}
2737
//---------------------------------------------------------------------------
2738
2739
template<typename Number>
2740
void Full_Cone<Number>::check_pointed() {
2741
if (isComputed(ConeProperty::IsPointed))
2742
return;
2743
assert(isComputed(ConeProperty::SupportHyperplanes));
2744
if (verbose) verboseOutput() << "Checking pointedness ... " << flush;
2745
2746
pointed = (Support_Hyperplanes.max_rank_submatrix_lex().size() == dim);
2747
is_Computed.set(ConeProperty::IsPointed);
2748
if (verbose) verboseOutput() << "done." << endl;
2749
}
2750
2751
2752
//---------------------------------------------------------------------------
2753
template<typename Number>
2754
void Full_Cone<Number>::disable_grading_dep_comp() {
2755
2756
if (do_multiplicity || do_deg1_elements || do_h_vector) {
2757
if (do_default_mode) {
2758
// if (verbose)
2759
// verboseOutput() << "No grading specified and cannot find one. "
2760
// << "Disabling some computations!" << endl;
2761
do_deg1_elements = false;
2762
do_h_vector = false;
2763
if(!explicit_full_triang){
2764
do_triangulation=false;
2765
do_partial_triangulation=true;
2766
}
2767
} else {
2768
throw BadInputException("No grading specified and cannot find one. Cannot compute some requested properties!");
2769
}
2770
}
2771
}
2772
2773
//---------------------------------------------------------------------------
2774
2775
/* computes a degree function, s.t. every generator has value >0 */
2776
template<typename Number>
2777
vector<Number> Full_Cone<Number>::compute_degree_function() const {
2778
size_t i;
2779
vector<Number> degree_function(dim,0);
2780
// add hyperplanes to get a degree function
2781
if(verbose) {
2782
verboseOutput()<<"computing degree function... "<<flush;
2783
}
2784
size_t h;
2785
for (h=0; h<Support_Hyperplanes.nr_of_rows(); ++h) {
2786
for (i=0; i<dim; i++) {
2787
degree_function[i] += Support_Hyperplanes.get_elem(h,i);
2788
}
2789
}
2790
v_simplify(degree_function);
2791
if(verbose) {
2792
verboseOutput()<<"done."<<endl;
2793
}
2794
return degree_function;
2795
}
2796
2797
//---------------------------------------------------------------------------
2798
// Constructors
2799
//---------------------------------------------------------------------------
2800
2801
template<typename Number>
2802
void Full_Cone<Number>::reset_tasks(){
2803
do_triangulation = false;
2804
do_partial_triangulation = false;
2805
do_determinants = false;
2806
do_multiplicity=false;
2807
do_integrally_closed = false;
2808
do_Hilbert_basis = false;
2809
do_deg1_elements = false;
2810
keep_triangulation = false;
2811
do_Stanley_dec=false;
2812
do_h_vector=false;
2813
do_hsop = false;
2814
do_excluded_faces=false;
2815
do_approximation=false;
2816
do_default_mode=false;
2817
do_class_group = false;
2818
do_module_gens_intcl = false;
2819
do_module_rank = false;
2820
do_cone_dec=false;
2821
stop_after_cone_dec=false;
2822
2823
do_extreme_rays=false;
2824
do_pointed=false;
2825
2826
do_evaluation = false;
2827
do_only_multiplicity=false;
2828
2829
use_bottom_points = true;
2830
2831
nrSimplicialPyr=0;
2832
totalNrPyr=0;
2833
is_pyramid = false;
2834
triangulation_is_nested = false;
2835
triangulation_is_partial = false;
2836
}
2837
2838
2839
//---------------------------------------------------------------------------
2840
2841
template<typename Number>
2842
Full_Cone<Number>::Full_Cone(const Matrix<Number>& M, bool do_make_prime){ // constructor of the top cone
2843
// do_make_prime left for syntax reasons, irrelevantant
2844
2845
dim=M.nr_of_columns();
2846
if(dim>0)
2847
Generators=M;
2848
// M.pretty_print(cout);
2849
// assert(M.row_echelon()== dim); rank check now done later
2850
2851
/*index=1; // not used at present
2852
for(size_t i=0;i<dim;++i)
2853
index*=M[i][i];
2854
index=Iabs(index); */
2855
2856
//make the generators coprime, remove 0 rows and duplicates
2857
has_generator_with_common_divisor = false; // irrelevant
2858
2859
Generators.simplify_rows();
2860
2861
Generators.remove_duplicate_and_zero_rows();
2862
nr_gen = Generators.nr_of_rows();
2863
2864
if (nr_gen != static_cast<size_t>(static_cast<key_t>(nr_gen))) {
2865
throw FatalException("Too many generators to fit in range of key_t!");
2866
}
2867
2868
// multiplicity = 0;
2869
is_Computed = bitset<ConeProperty::EnumSize>(); //initialized to false
2870
is_Computed.set(ConeProperty::Generators);
2871
pointed = false;
2872
is_simplicial = nr_gen == dim;
2873
deg1_extreme_rays = false;
2874
deg1_generated = false;
2875
deg1_generated_computed = false;
2876
deg1_hilbert_basis = false;
2877
2878
reset_tasks();
2879
2880
Extreme_Rays_Ind = vector<bool>(nr_gen,false);
2881
in_triang = vector<bool> (nr_gen,false);
2882
deg1_triangulation = true;
2883
if(dim==0){ //correction needed to include the 0 cone;
2884
is_Computed.set(ConeProperty::Triangulation);
2885
}
2886
pyr_level=-1;
2887
Top_Cone=this;
2888
Top_Key.resize(nr_gen);
2889
for(size_t i=0;i<nr_gen;i++)
2890
Top_Key[i]=i;
2891
totalNrSimplices=0;
2892
TriangulationBufferSize=0;
2893
2894
detSum = 0;
2895
shift = 0;
2896
2897
FS.resize(omp_get_max_threads());
2898
2899
Pyramids.resize(20); // prepare storage for pyramids
2900
nrPyramids.resize(20,0);
2901
2902
recursion_allowed=true;
2903
2904
do_all_hyperplanes=true;
2905
// multithreaded_pyramid=true; now in build_cone where it is defined dynamically
2906
2907
2908
nextGen=0;
2909
store_level=0;
2910
2911
Comparisons.reserve(nr_gen);
2912
nrTotalComparisons=0;
2913
2914
inhomogeneous=false;
2915
2916
level0_dim=dim; // must always be defined
2917
2918
use_existing_facets=false;
2919
start_from=0;
2920
old_nr_supp_hyps=0;
2921
2922
verbose=false;
2923
2924
RankTest = vector< Matrix<Number> >(omp_get_max_threads(), Matrix<Number>(0,dim));
2925
2926
do_bottom_dec=false;
2927
suppress_bottom_dec=false;
2928
keep_order=false;
2929
2930
approx_level = 1;
2931
is_approximation=false;
2932
2933
PermGens.resize(nr_gen);
2934
for(size_t i=0;i<nr_gen;++i)
2935
PermGens[i]=i;
2936
}
2937
2938
//---------------------------------------------------------------------------
2939
2940
/* constructor for pyramids */
2941
template<typename Number>
2942
Full_Cone<Number>::Full_Cone(Full_Cone<Number>& C, const vector<key_t>& Key) {
2943
2944
Generators = C.Generators.submatrix(Key);
2945
dim = Generators.nr_of_columns();
2946
nr_gen = Generators.nr_of_rows();
2947
has_generator_with_common_divisor = C.has_generator_with_common_divisor;
2948
is_simplicial = nr_gen == dim;
2949
2950
Top_Cone=C.Top_Cone; // relate to top cone
2951
Top_Key.resize(nr_gen);
2952
for(size_t i=0;i<nr_gen;i++)
2953
Top_Key[i]=C.Top_Key[Key[i]];
2954
2955
// multiplicity = 0;
2956
2957
Extreme_Rays_Ind = vector<bool>(nr_gen,false);
2958
is_Computed.set(ConeProperty::ExtremeRays, C.isComputed(ConeProperty::ExtremeRays));
2959
if(isComputed(ConeProperty::ExtremeRays))
2960
for(size_t i=0;i<nr_gen;i++)
2961
Extreme_Rays_Ind[i]=C.Extreme_Rays_Ind[Key[i]];
2962
in_triang = vector<bool> (nr_gen,false);
2963
deg1_triangulation = true;
2964
2965
// not used in a pyramid, but set precaution
2966
deg1_extreme_rays = false;
2967
deg1_generated = false;
2968
deg1_generated_computed = false;
2969
deg1_hilbert_basis = false;
2970
2971
Grading=C.Grading;
2972
is_Computed.set(ConeProperty::Grading, C.isComputed(ConeProperty::Grading));
2973
Order_Vector=C.Order_Vector;
2974
2975
do_extreme_rays=false;
2976
do_triangulation=C.do_triangulation;
2977
do_partial_triangulation=C.do_partial_triangulation;
2978
do_determinants=C.do_determinants;
2979
do_multiplicity=C.do_multiplicity;
2980
do_deg1_elements=C.do_deg1_elements;
2981
do_h_vector=C.do_h_vector;
2982
do_Hilbert_basis=C.do_Hilbert_basis;
2983
keep_triangulation=C.keep_triangulation;
2984
do_only_multiplicity=C.do_only_multiplicity;
2985
do_evaluation=C.do_evaluation;
2986
do_Stanley_dec=C.do_Stanley_dec;
2987
inhomogeneous=C.inhomogeneous; // at present not used in proper pyramids
2988
is_pyramid=true;
2989
2990
pyr_level=C.pyr_level+1;
2991
2992
totalNrSimplices=0;
2993
detSum = 0;
2994
shift = C.shift;
2995
if(C.gen_degrees.size()>0){ // now we copy the degrees
2996
gen_degrees.resize(nr_gen);
2997
for (size_t i=0; i<nr_gen; i++) {
2998
gen_degrees[i] = C.gen_degrees[Key[i]];
2999
}
3000
}
3001
if(C.gen_levels.size()>0){ // now we copy the levels
3002
gen_levels.resize(nr_gen);
3003
for (size_t i=0; i<nr_gen; i++) {
3004
gen_levels[i] = C.gen_levels[Key[i]];
3005
}
3006
}
3007
TriangulationBufferSize=0;
3008
3009
3010
recursion_allowed=C.recursion_allowed; // must be reset if necessary
3011
do_all_hyperplanes=true; // must be reset for non-recursive pyramids
3012
// multithreaded_pyramid=false; // SEE ABOVE
3013
3014
nextGen=0;
3015
store_level = C.store_level;
3016
3017
Comparisons.reserve(nr_gen);
3018
nrTotalComparisons=0;
3019
3020
level0_dim = C.level0_dim; // must always be defined
3021
3022
use_existing_facets=false;
3023
start_from=0;
3024
old_nr_supp_hyps=0;
3025
verbose=false;
3026
3027
approx_level = C.approx_level;
3028
is_approximation = C.is_approximation;
3029
3030
do_bottom_dec=false;
3031
suppress_bottom_dec=false;
3032
keep_order=true;
3033
}
3034
3035
//---------------------------------------------------------------------------
3036
3037
template<typename Number>
3038
void Full_Cone<Number>::set_zero_cone() {
3039
3040
assert(dim==0);
3041
3042
if (verbose) {
3043
verboseOutput() << "Zero cone detected!" << endl;
3044
}
3045
3046
// The basis change already is transforming to zero.
3047
is_Computed.set(ConeProperty::Sublattice);
3048
is_Computed.set(ConeProperty::Generators);
3049
is_Computed.set(ConeProperty::ExtremeRays);
3050
Support_Hyperplanes=Matrix<Number> (0);
3051
is_Computed.set(ConeProperty::SupportHyperplanes);
3052
totalNrSimplices = 0;
3053
is_Computed.set(ConeProperty::TriangulationSize);
3054
detSum = 0;
3055
is_Computed.set(ConeProperty::Triangulation);
3056
3057
pointed = true;
3058
is_Computed.set(ConeProperty::IsPointed);
3059
3060
deg1_extreme_rays = true;
3061
is_Computed.set(ConeProperty::IsDeg1ExtremeRays);
3062
3063
if (inhomogeneous) { // empty set of solutions
3064
is_Computed.set(ConeProperty::VerticesOfPolyhedron);
3065
module_rank = 0;
3066
is_Computed.set(ConeProperty::ModuleRank);
3067
is_Computed.set(ConeProperty::ModuleGenerators);
3068
level0_dim=0;
3069
is_Computed.set(ConeProperty::RecessionRank);
3070
}
3071
}
3072
3073
//---------------------------------------------------------------------------
3074
3075
template<typename Number>
3076
bool Full_Cone<Number>::isComputed(ConeProperty::Enum prop) const{
3077
return is_Computed.test(prop);
3078
}
3079
3080
//---------------------------------------------------------------------------
3081
// Data access
3082
//---------------------------------------------------------------------------
3083
3084
template<typename Number>
3085
size_t Full_Cone<Number>::getDimension()const{
3086
return dim;
3087
}
3088
3089
//---------------------------------------------------------------------------
3090
3091
template<typename Number>
3092
size_t Full_Cone<Number>::getNrGenerators()const{
3093
return nr_gen;
3094
}
3095
3096
//---------------------------------------------------------------------------
3097
3098
template<typename Number>
3099
bool Full_Cone<Number>::isPointed()const{
3100
return pointed;
3101
}
3102
3103
//---------------------------------------------------------------------------
3104
3105
template<typename Number>
3106
bool Full_Cone<Number>::isDeg1ExtremeRays() const{
3107
return deg1_extreme_rays;
3108
}
3109
3110
//---------------------------------------------------------------------------
3111
3112
template<typename Number>
3113
size_t Full_Cone<Number>::getModuleRank()const{
3114
return module_rank;
3115
}
3116
3117
3118
//---------------------------------------------------------------------------
3119
3120
template<typename Number>
3121
const Matrix<Number>& Full_Cone<Number>::getGenerators()const{
3122
return Generators;
3123
}
3124
3125
//---------------------------------------------------------------------------
3126
3127
template<typename Number>
3128
vector<bool> Full_Cone<Number>::getExtremeRays()const{
3129
return Extreme_Rays_Ind;
3130
}
3131
3132
//---------------------------------------------------------------------------
3133
3134
template<typename Number>
3135
Matrix<Number> Full_Cone<Number>::getSupportHyperplanes()const{
3136
return Support_Hyperplanes;
3137
}
3138
3139
//---------------------------------------------------------------------------
3140
3141
template<typename Number>
3142
void Full_Cone<Number>::error_msg(string s) const{
3143
errorOutput() <<"\nFull Cone "<< s<<"\n";
3144
}
3145
3146
//---------------------------------------------------------------------------
3147
3148
template<typename Number>
3149
void Full_Cone<Number>::print()const{
3150
verboseOutput()<<"\ndim="<<dim<<".\n";
3151
verboseOutput()<<"\nnr_gen="<<nr_gen<<".\n";
3152
// verboseOutput()<<"\nhyp_size="<<hyp_size<<".\n";
3153
verboseOutput()<<"\nGrading is:\n";
3154
verboseOutput()<< Grading;
3155
// verboseOutput()<<"\nMultiplicity is "<<multiplicity<<".\n";
3156
verboseOutput()<<"\nGenerators are:\n";
3157
Generators.pretty_print(verboseOutput());
3158
verboseOutput()<<"\nExtreme_rays are:\n";
3159
verboseOutput()<< Extreme_Rays_Ind;
3160
verboseOutput()<<"\nSupport Hyperplanes are:\n";
3161
Support_Hyperplanes.pretty_print(verboseOutput());
3162
verboseOutput()<<"\nHilbert basis is:\n";
3163
verboseOutput()<< Hilbert_Basis;
3164
verboseOutput()<<"\nDeg1 elements are:\n";
3165
verboseOutput()<< Deg1_Elements;
3166
}
3167
3168
} //end namespace
3169
3170