Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

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

563624 views
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 <vector>
28
#include <map>
29
#include <set>
30
#include <iostream>
31
#include <string>
32
#include <algorithm>
33
34
#include "libnormaliz/cone_dual_mode.h"
35
#include "libnormaliz/vector_operations.h"
36
#include "libnormaliz/list_operations.h"
37
38
//---------------------------------------------------------------------------
39
40
namespace libnormaliz {
41
using namespace std;
42
43
//---------------------------------------------------------------------------
44
//private
45
//---------------------------------------------------------------------------
46
47
template<typename Integer>
48
void Cone_Dual_Mode<Integer>::splice_them_sort(CandidateList< Integer>& Total, vector<CandidateList< Integer> >& Parts){
49
50
CandidateList<Integer> New;
51
New.verbose=verbose;
52
New.dual=true;
53
for(int i=0;i<omp_get_max_threads();i++)
54
New.Candidates.splice(New.Candidates.end(),Parts[i].Candidates);
55
New.sort_by_val();
56
New.unique_vectors();
57
Total.merge_by_val(New);
58
}
59
60
//---------------------------------------------------------------------------
61
62
template<typename Integer>
63
void Cone_Dual_Mode<Integer>::select_HB(CandidateList<Integer>& Cand, size_t guaranteed_HB_deg,
64
CandidateList<Integer>& Irred, bool all_irreducible){
65
66
if(all_irreducible){
67
Irred.merge_by_val(Cand);
68
return;
69
}
70
71
typename list<Candidate<Integer> >::iterator h;
72
for(h=Cand.Candidates.begin(); h!=Cand.Candidates.end();){
73
if(h->old_tot_deg<=guaranteed_HB_deg){
74
Irred.Candidates.splice(Irred.Candidates.end(),Cand.Candidates,h++);
75
}
76
else{
77
++h;
78
}
79
}
80
Irred.auto_reduce_sorted(); // necessary since the guaranteed HB degree only determines
81
// in which degrees we can already decide whether an element belongs to the HB
82
}
83
84
85
//---------------------------------------------------------------------------
86
87
88
//public
89
//---------------------------------------------------------------------------
90
91
template<typename Integer>
92
Cone_Dual_Mode<Integer>::Cone_Dual_Mode(Matrix<Integer>& M, const vector<Integer>& Truncation){
93
dim=M.nr_of_columns();
94
M.remove_duplicate_and_zero_rows();
95
// now we sort by L_1-norm and then lex
96
Matrix<Integer> Weights(0,dim);
97
vector<bool> absolute;
98
Weights.append(vector<Integer>(dim,1));
99
absolute.push_back(true);
100
vector<key_t> perm=M.perm_by_weights(Weights,absolute);
101
M.order_rows_by_perm(perm);
102
103
SupportHyperplanes=Matrix<Integer>(0,dim);
104
BasisMaxSubspace=Matrix<Integer>(dim); // dim x dim identity matrix
105
if(Truncation.size()!=0){
106
vector<Integer> help=Truncation;
107
v_make_prime(help); // truncation need not be coprime
108
M.remove_row(help); // remove truncation if it should be a support hyperplane
109
SupportHyperplanes.append(Truncation); // now we insert it again as the first hyperplane
110
}
111
SupportHyperplanes.append(M);
112
nr_sh = SupportHyperplanes.nr_of_rows();
113
114
verbose = false;
115
inhomogeneous = false;
116
do_only_Deg1_Elements = false;
117
truncate = false;
118
119
Intermediate_HB.dual=true;
120
121
if (nr_sh != static_cast<size_t>(static_cast<key_t>(nr_sh))) {
122
throw FatalException("Too many support hyperplanes to fit in range of key_t!");
123
}
124
}
125
126
//---------------------------------------------------------------------------
127
128
template<typename Integer>
129
Matrix<Integer> Cone_Dual_Mode<Integer>::get_support_hyperplanes() const {
130
return SupportHyperplanes;
131
}
132
133
//---------------------------------------------------------------------------
134
135
template<typename Integer>
136
Matrix<Integer> Cone_Dual_Mode<Integer>::get_generators()const{
137
return Generators;
138
}
139
140
template<typename Integer>
141
vector<bool> Cone_Dual_Mode<Integer>::get_extreme_rays() const{
142
return ExtremeRaysInd;
143
144
}
145
146
147
size_t counter=0,counter1=0, counter2=0;
148
149
const size_t ReportBound=100000;
150
151
//---------------------------------------------------------------------------
152
153
// In the inhomogeneous case or when only degree 1 elements are to be found,
154
// we truncate the Hilbert basis at level 1. The level is the ordinary degree
155
// for degree 1 elements and the degree of the homogenizing variable
156
// in the inhomogeneous case.
157
//
158
// As soon as there are no positive or neutral (with respect to the current hyperplane)
159
// elements in the current Hilbert basis and truncate==true, new elements can only
160
// be produced as sums of positive irreds of level 1 and negative irreds of level 0.
161
// In particular no new negative elements can be produced, and the only type of
162
// reduction on the positive side is the elimination of duplicates.
163
//
164
// If there are no elements on level 0 at all, then new elements cannot be produced anymore,
165
// and the production of new elements can be skipped.
166
167
template<typename Integer>
168
void Cone_Dual_Mode<Integer>::cut_with_halfspace_hilbert_basis(const size_t& hyp_counter,
169
const bool lifting, vector<Integer>& old_lin_subspace_half, bool pointed){
170
if (verbose==true) {
171
verboseOutput()<<"==================================================" << endl;
172
verboseOutput()<<"cut with halfspace "<<hyp_counter+1 <<" ..."<<endl;
173
}
174
175
size_t i;
176
int sign;
177
178
CandidateList<Integer> Positive_Irred(true),Negative_Irred(true),Neutral_Irred(true); // for the Hilbert basis elements
179
Positive_Irred.verbose=Negative_Irred.verbose=Neutral_Irred.verbose=verbose;
180
list<Candidate<Integer>* > Pos_Gen0, Pos_Gen1, Neg_Gen0, Neg_Gen1; // pointer lists for generation control
181
size_t pos_gen0_size=0, pos_gen1_size=0, neg_gen0_size=0, neg_gen1_size=0;
182
183
Integer orientation, scalar_product,diff,factor;
184
vector <Integer> hyperplane=SupportHyperplanes[hyp_counter]; // the current hyperplane dividing the old cone
185
typename list<Candidate<Integer> >::iterator h;
186
187
if (lifting==true) {
188
orientation=v_scalar_product<Integer>(hyperplane,old_lin_subspace_half);
189
if(orientation<0){
190
orientation=-orientation;
191
v_scalar_multiplication<Integer>(old_lin_subspace_half,-1); //transforming into the generator of the positive half of the old max lin subsapce
192
}
193
// from now on orientation > 0
194
195
for (h = Intermediate_HB.Candidates.begin(); h != Intermediate_HB.Candidates.end(); ++h) { //reduction modulo the generators of the two halves of the old max lin subspace
196
scalar_product=v_scalar_product(hyperplane,h->cand); // allows us to declare "old" HB candiadtes as irreducible
197
sign=1;
198
if (scalar_product<0) {
199
scalar_product=-scalar_product;
200
sign=-1;
201
}
202
factor=scalar_product/orientation; // we reduce all elements by the generator of the halfspace
203
for (i = 0; i < dim; i++) {
204
h->cand[i]=h->cand[i]-sign*factor*old_lin_subspace_half[i];
205
}
206
}
207
208
//adding the generators of the halves of the old max lin subspaces to the the "positive" and the "negative" generators
209
// ABSOLUTELY NECESSARY since we need a monoid system of generators of the full "old" cone
210
211
Candidate<Integer> halfspace_gen_as_cand(old_lin_subspace_half,nr_sh);
212
halfspace_gen_as_cand.mother=0;
213
// halfspace_gen_as_cand.father=0;
214
halfspace_gen_as_cand.old_tot_deg=0;
215
(halfspace_gen_as_cand.values)[hyp_counter]=orientation; // value under the new linear form
216
halfspace_gen_as_cand.sort_deg=convertTo<long>(orientation);
217
assert(orientation!=0);
218
if(!truncate || halfspace_gen_as_cand.values[0] <=1){ // the only critical case is the positive halfspace gen in round 0
219
Positive_Irred.push_back(halfspace_gen_as_cand); // it must have value <= 1 under the truncation.
220
Pos_Gen0.push_back(&Positive_Irred.Candidates.front()); // Later on all these elements have value 0 under it.
221
pos_gen0_size=1;
222
}
223
v_scalar_multiplication<Integer>(halfspace_gen_as_cand.cand,-1);
224
Negative_Irred.push_back(halfspace_gen_as_cand);
225
Neg_Gen0.push_back(&Negative_Irred.Candidates.front());
226
neg_gen0_size=1;
227
} //end lifting
228
229
long gen0_mindeg; // minimal degree of a generator
230
if(lifting)
231
gen0_mindeg=0; // sort_deg has already been set > 0 for half_space_gen
232
else
233
gen0_mindeg=Intermediate_HB.Candidates.begin()->sort_deg;
234
typename list<Candidate<Integer> >::const_iterator hh;
235
for(hh=Intermediate_HB.Candidates.begin();hh!=Intermediate_HB.Candidates.end();++hh)
236
if(hh->sort_deg < gen0_mindeg)
237
gen0_mindeg=hh->sort_deg;
238
239
bool gen1_pos=false, gen1_neg=false;
240
bool no_pos_in_level0=pointed;
241
bool all_positice_level=pointed;
242
for (h = Intermediate_HB.Candidates.begin(); h != Intermediate_HB.Candidates.end(); ++h) { //dividing into negative and positive
243
Integer new_val=v_scalar_product<Integer>(hyperplane,h->cand);
244
long new_val_long=convertTo<long>(new_val);
245
h->reducible=false;
246
h->mother=0;
247
// h->father=0;
248
h->old_tot_deg=h->sort_deg;
249
if (new_val>0) {
250
gen1_pos=true;
251
h->values[hyp_counter]=new_val;
252
h->sort_deg+=new_val_long;
253
Positive_Irred.Candidates.push_back(*h); // could be spliced
254
Pos_Gen1.push_back(&Positive_Irred.Candidates.back());
255
pos_gen1_size++;
256
if(h->values[0]==0){
257
no_pos_in_level0=false;
258
all_positice_level=false;
259
}
260
}
261
if (new_val<0) {
262
gen1_neg=true;
263
h->values[hyp_counter]=-new_val;
264
h->sort_deg+=-new_val_long;
265
Negative_Irred.Candidates.push_back(*h);
266
Neg_Gen1.push_back(&Negative_Irred.Candidates.back());
267
neg_gen1_size++;
268
if(h->values[0]==0){
269
all_positice_level=false;
270
}
271
}
272
if (new_val==0) {
273
Neutral_Irred.Candidates.push_back(*h);
274
if(h->values[0]==0){
275
no_pos_in_level0=false;
276
all_positice_level=false;
277
}
278
}
279
}
280
281
282
if((truncate && (no_pos_in_level0 && !all_positice_level))){
283
if(verbose){
284
verboseOutput() << "Eliminating negative generators of level > 0" << endl;
285
}
286
Neg_Gen1.clear();
287
neg_gen1_size=0;
288
for (h = Negative_Irred.Candidates.begin(); h != Negative_Irred.Candidates.end();){
289
if(h->values[0]>0)
290
h=Negative_Irred.Candidates.erase(h);
291
else{
292
Neg_Gen1.push_back(&(*h));
293
neg_gen1_size++;
294
++h;
295
}
296
}
297
}
298
299
#ifndef NCATCH
300
std::exception_ptr tmp_exception;
301
#endif
302
303
#pragma omp parallel num_threads(3)
304
{
305
306
#pragma omp single nowait
307
{
308
#ifndef NCATCH
309
try {
310
#endif
311
check_range_list(Negative_Irred);
312
Negative_Irred.sort_by_val();
313
Negative_Irred.last_hyp=hyp_counter;
314
#ifndef NCATCH
315
} catch(const std::exception& ) {
316
tmp_exception = std::current_exception();
317
}
318
#endif
319
}
320
321
#pragma omp single nowait
322
{
323
#ifndef NCATCH
324
try {
325
#endif
326
check_range_list(Positive_Irred);
327
Positive_Irred.sort_by_val();
328
Positive_Irred.last_hyp=hyp_counter;
329
#ifndef NCATCH
330
} catch(const std::exception& ) {
331
tmp_exception = std::current_exception();
332
}
333
#endif
334
}
335
336
#pragma omp single nowait
337
{
338
Neutral_Irred.sort_by_val();
339
Neutral_Irred.last_hyp=hyp_counter;
340
}
341
}
342
#ifndef NCATCH
343
if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);
344
#endif
345
346
CandidateList<Integer> New_Positive_Irred(true),New_Negative_Irred(true),New_Neutral_Irred(true);
347
New_Positive_Irred.verbose=New_Negative_Irred.verbose=New_Neutral_Irred.verbose=verbose;
348
New_Negative_Irred.last_hyp=hyp_counter; // for the newly generated vector in each thread
349
New_Positive_Irred.last_hyp=hyp_counter;
350
New_Neutral_Irred.last_hyp=hyp_counter;
351
352
CandidateList<Integer> Positive_Depot(true),Negative_Depot(true),Neutral_Depot(true); // to store the new vectors after generation
353
Positive_Depot.verbose=Negative_Depot.verbose=Neutral_Depot.verbose=verbose;
354
355
vector<CandidateList<Integer> > New_Positive_thread(omp_get_max_threads()),
356
New_Negative_thread(omp_get_max_threads()),
357
New_Neutral_thread(omp_get_max_threads());
358
359
vector<CandidateTable<Integer> > Pos_Table, Neg_Table, Neutr_Table; // for reduction in each thread
360
361
for(long i=0;i<omp_get_max_threads();++i){
362
New_Positive_thread[i].dual=true;
363
New_Positive_thread[i].verbose=verbose;
364
New_Negative_thread[i].dual=true;
365
New_Negative_thread[i].verbose=verbose;
366
New_Neutral_thread[i].dual=true;
367
New_Neutral_thread[i].verbose=verbose;
368
}
369
370
for(int k=0;k<omp_get_max_threads();++k){
371
Pos_Table.push_back(CandidateTable<Integer>(Positive_Irred));
372
Neg_Table.push_back(CandidateTable<Integer>(Negative_Irred));
373
Neutr_Table.push_back(CandidateTable<Integer>(Neutral_Irred));
374
}
375
376
typename list<Candidate<Integer>* >::iterator n,p;
377
Candidate<Integer> *p_cand, *n_cand;
378
// typename list<Candidate<Integer> >::iterator c;
379
380
bool not_done;
381
if(lifting)
382
not_done=gen1_pos || gen1_neg;
383
else
384
not_done=gen1_pos && gen1_neg;
385
386
bool do_reduction=!(truncate && no_pos_in_level0);
387
388
bool do_only_selection=truncate && all_positice_level;
389
390
size_t round=0;
391
392
if(do_only_selection){
393
pos_gen0_size=pos_gen1_size; // otherwise wrong sizes in message at the end
394
neg_gen0_size=neg_gen1_size;
395
}
396
397
while(not_done && !do_only_selection) {
398
399
//generating new elements
400
round++;
401
402
typename list<Candidate<Integer>* >::iterator pos_begin, pos_end, neg_begin, neg_end;
403
size_t pos_size, neg_size;
404
405
// Steps are:
406
// 0: old pos vs. new neg
407
// 1: new pos vs. old neg
408
// 2: new pos vs. new neg
409
for(size_t step=0;step<=2;step++)
410
{
411
412
if(step==0){
413
pos_begin=Pos_Gen0.begin();
414
pos_end=Pos_Gen0.end();
415
neg_begin=Neg_Gen1.begin();
416
neg_end=Neg_Gen1.end();
417
pos_size=pos_gen0_size;
418
neg_size=neg_gen1_size;
419
}
420
421
if(step==1){
422
pos_begin=Pos_Gen1.begin();
423
pos_end=Pos_Gen1.end();
424
neg_begin=Neg_Gen0.begin();
425
neg_end=Neg_Gen0.end();
426
pos_size=pos_gen1_size;
427
neg_size=neg_gen0_size;;
428
}
429
430
if(step==2){
431
pos_begin=Pos_Gen1.begin();
432
pos_end=Pos_Gen1.end();
433
neg_begin=Neg_Gen1.begin();
434
neg_end=Neg_Gen1.end();
435
pos_size=pos_gen1_size;
436
neg_size=neg_gen1_size;
437
}
438
439
if(pos_size==0 || neg_size==0)
440
continue;
441
442
vector<typename list<Candidate<Integer>* >::iterator > PosBlockStart, NegBlockStart;
443
444
const size_t Blocksize=200;
445
446
size_t nr_in_block=0, pos_block_nr=0;
447
for(p=pos_begin;p!=pos_end;++p){
448
if(nr_in_block%Blocksize==0){
449
PosBlockStart.push_back(p);
450
pos_block_nr++;
451
nr_in_block=0;
452
}
453
nr_in_block++;
454
}
455
PosBlockStart.push_back(p);
456
457
nr_in_block=0;
458
size_t neg_block_nr=0;
459
for(n=neg_begin;n!=neg_end;++n){
460
if(nr_in_block%Blocksize==0){
461
NegBlockStart.push_back(n);
462
neg_block_nr++;
463
nr_in_block=0;
464
}
465
nr_in_block++;
466
}
467
NegBlockStart.push_back(n);
468
469
// cout << "Step " << step << " pos " << pos_size << " neg " << neg_size << endl;
470
471
if (verbose) {
472
// size_t neg_size=Negative_Irred.size();
473
// size_t zsize=Neutral_Irred.size();
474
if (pos_size*neg_size>=ReportBound)
475
verboseOutput()<<"Positive: "<<pos_size<<" Negative: "<<neg_size<< endl;
476
else{
477
if(round%100==0)
478
verboseOutput() << "Round " << round << endl;
479
}
480
}
481
482
bool skip_remaining = false;
483
484
const long VERBOSE_STEPS = 50;
485
long step_x_size = pos_block_nr*neg_block_nr-VERBOSE_STEPS;
486
487
#pragma omp parallel private(p,n,diff,p_cand,n_cand)
488
{
489
Candidate<Integer> new_candidate(dim,nr_sh);
490
491
size_t total=pos_block_nr*neg_block_nr;
492
493
#pragma omp for schedule(dynamic)
494
for(size_t bb=0;bb<total;++bb){ // main loop over the blocks
495
496
if (skip_remaining) continue;
497
498
#ifndef NCATCH
499
try {
500
#endif
501
502
INTERRUPT_COMPUTATION_BY_EXCEPTION
503
504
if(verbose && pos_size*neg_size>=ReportBound){
505
#pragma omp critical(VERBOSE)
506
while ((long)(bb*VERBOSE_STEPS) >= step_x_size) {
507
step_x_size += total;
508
verboseOutput() << "." <<flush;
509
}
510
511
}
512
513
size_t nr_pos=bb/neg_block_nr;
514
size_t nr_neg=bb%neg_block_nr;
515
516
for(p=PosBlockStart[nr_pos];p!=PosBlockStart[nr_pos+1];++p){
517
518
519
p_cand=*p;
520
521
Integer pos_val=p_cand->values[hyp_counter];
522
523
for (n= NegBlockStart[nr_neg];n!=NegBlockStart[nr_neg+1]; ++n){
524
525
n_cand=*n;
526
527
if(truncate && p_cand->values[0]+n_cand->values[0] >=2) // in the inhomogeneous case we truncate at level 1
528
continue;
529
530
Integer neg_val=n_cand->values[hyp_counter];
531
diff=pos_val-neg_val;
532
533
// prediction of reducibility
534
535
if (diff >0 && n_cand->mother!=0 &&
536
(
537
n_cand->mother<=pos_val // sum of p_cand and n_cand would be irreducible by mother + the vector on the opposite side
538
|| (p_cand->mother >= n_cand->mother && p_cand->mother-n_cand->mother <=diff) // sum would reducible ny mother + mother
539
)
540
){
541
// #pragma omp atomic
542
// counter1++;
543
continue;
544
}
545
546
547
if ( diff <0 && p_cand->mother!=0 &&
548
(
549
p_cand->mother<=neg_val
550
|| (n_cand->mother >= p_cand->mother && n_cand->mother-p_cand->mother <= -diff)
551
)
552
){
553
// #pragma omp atomic // sum would be irreducible by mother + the vector on the opposite side
554
// counter1++;
555
continue;
556
}
557
558
if(diff==0 && p_cand->mother!=0 && n_cand->mother == p_cand->mother){
559
// #pragma omp atomic
560
// counter1++;
561
continue;
562
}
563
564
// #pragma omp atomic
565
// counter++;
566
567
new_candidate.old_tot_deg=p_cand->old_tot_deg+n_cand->old_tot_deg;
568
v_add_result(new_candidate.values,hyp_counter,p_cand->values,n_cand->values); // new_candidate=v_add
569
570
if (diff>0) {
571
new_candidate.values[hyp_counter]=diff;
572
new_candidate.sort_deg=p_cand->sort_deg+n_cand->sort_deg-2*convertTo<long>(neg_val);
573
if(do_reduction && (Pos_Table[omp_get_thread_num()].is_reducible_unordered(new_candidate) ||
574
Neutr_Table[omp_get_thread_num()].is_reducible_unordered(new_candidate)))
575
continue;
576
v_add_result(new_candidate.cand,dim,p_cand->cand,n_cand->cand);
577
new_candidate.mother=pos_val;
578
// new_candidate.father=neg_val;
579
New_Positive_thread[omp_get_thread_num()].push_back(new_candidate);
580
}
581
if (diff<0) {
582
if(!do_reduction) // don't need new negative elements anymore
583
continue;
584
new_candidate.values[hyp_counter]=-diff;
585
new_candidate.sort_deg=p_cand->sort_deg+n_cand->sort_deg-2*convertTo<long>(pos_val);
586
if(Neg_Table[omp_get_thread_num()].is_reducible_unordered(new_candidate)) {
587
continue;
588
}
589
if(Neutr_Table[omp_get_thread_num()].is_reducible_unordered(new_candidate)) {
590
continue;
591
}
592
v_add_result(new_candidate.cand,dim,p_cand->cand,n_cand->cand);
593
new_candidate.mother=neg_val;
594
// new_candidate.father=pos_val;
595
New_Negative_thread[omp_get_thread_num()].push_back(new_candidate);
596
}
597
if (diff==0) {
598
new_candidate.values[hyp_counter]=0;
599
new_candidate.sort_deg=p_cand->sort_deg+n_cand->sort_deg-2*convertTo<long>(pos_val); //pos_val==neg_val
600
if(do_reduction && Neutr_Table[omp_get_thread_num()].is_reducible_unordered(new_candidate)) {
601
continue;
602
}
603
v_add_result(new_candidate.cand,dim,p_cand->cand,n_cand->cand);
604
// new_candidate.mother=0; // irrelevant
605
New_Neutral_thread[omp_get_thread_num()].push_back(new_candidate);
606
}
607
} // neg
608
609
} // pos
610
611
#ifndef NCATCH
612
} catch(const std::exception& ) {
613
tmp_exception = std::current_exception();
614
skip_remaining = true;
615
#pragma omp flush(skip_remaining)
616
}
617
#endif
618
619
} // bb, end generation of new elements
620
621
#pragma omp single
622
{
623
if(verbose && pos_size*neg_size>=ReportBound)
624
verboseOutput() << endl;
625
}
626
627
} //END PARALLEL
628
629
#ifndef NCATCH
630
if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);
631
#endif
632
633
} // steps
634
635
Pos_Gen0.splice(Pos_Gen0.end(),Pos_Gen1); // the new generation has become old
636
pos_gen0_size+=pos_gen1_size;
637
pos_gen1_size=0;
638
Neg_Gen0.splice(Neg_Gen0.end(),Neg_Gen1);
639
neg_gen0_size+=neg_gen1_size;
640
neg_gen1_size=0;
641
642
splice_them_sort(Neutral_Depot,New_Neutral_thread); // sort by sort_deg and values
643
644
splice_them_sort(Positive_Depot,New_Positive_thread);
645
646
splice_them_sort(Negative_Depot,New_Negative_thread);
647
648
if(Positive_Depot.empty() && Negative_Depot.empty())
649
not_done=false;
650
651
// Attention: the element with smallest old_tot_deg need not be the first in the list which is ordered by sort_deg
652
size_t gen1_mindeg=0; // minimal old_tot_deg of a new element used for generation
653
bool first=true;
654
typename list<Candidate<Integer> >::iterator c;
655
for(c = Positive_Depot.Candidates.begin();c!=Positive_Depot.Candidates.end();++c){
656
if(first){
657
first=false;
658
gen1_mindeg=c->old_tot_deg;
659
}
660
if(c->old_tot_deg<gen1_mindeg)
661
gen1_mindeg=c->old_tot_deg;
662
}
663
664
for(c = Negative_Depot.Candidates.begin();c!=Negative_Depot.Candidates.end();++c){
665
if(first){
666
first=false;
667
gen1_mindeg=c->old_tot_deg;
668
}
669
if(c->old_tot_deg<gen1_mindeg)
670
gen1_mindeg=c->old_tot_deg;
671
672
}
673
674
size_t min_deg_new=gen0_mindeg+gen1_mindeg;
675
if(not_done)
676
assert(min_deg_new>0);
677
678
size_t all_known_deg=min_deg_new-1;
679
size_t guaranteed_HB_deg=2*all_known_deg+1; // the degree up to which we can decide whether an element belongs to the HB
680
681
if(not_done){
682
select_HB(Neutral_Depot,guaranteed_HB_deg,New_Neutral_Irred,!do_reduction);
683
}
684
else{
685
Neutral_Depot.auto_reduce_sorted(); // in this case new elements will not be produced anymore
686
Neutral_Irred.merge_by_val(Neutral_Depot); // and there is nothing to do for positive or negative elements
687
// but the remaining neutral elements must be auto-reduced.
688
}
689
690
CandidateTable<Integer> New_Pos_Table(true,hyp_counter), New_Neg_Table(true,hyp_counter), New_Neutr_Table(true,hyp_counter);
691
// for new elements
692
693
if (!New_Neutral_Irred.empty()) {
694
if(do_reduction){
695
Positive_Depot.reduce_by(New_Neutral_Irred);
696
Neutral_Depot.reduce_by(New_Neutral_Irred);
697
}
698
Negative_Depot.reduce_by(New_Neutral_Irred);
699
list<Candidate<Integer>* > New_Elements;
700
Neutral_Irred.merge_by_val(New_Neutral_Irred,New_Elements);
701
typename list<Candidate<Integer>* >::iterator c;
702
for(c=New_Elements.begin(); c!=New_Elements.end(); ++c){
703
New_Neutr_Table.ValPointers.push_back(pair< size_t, vector<Integer>* >((*c)->sort_deg,&((*c)->values)));
704
}
705
New_Elements.clear();
706
}
707
708
select_HB(Positive_Depot,guaranteed_HB_deg,New_Positive_Irred,!do_reduction);
709
710
select_HB(Negative_Depot,guaranteed_HB_deg,New_Negative_Irred,!do_reduction);
711
712
if (!New_Positive_Irred.empty()) {
713
if(do_reduction)
714
Positive_Depot.reduce_by(New_Positive_Irred);
715
check_range_list(New_Positive_Irred); // check for danger of overflow
716
Positive_Irred.merge_by_val(New_Positive_Irred,Pos_Gen1);
717
typename list<Candidate<Integer>* >::iterator c;
718
for(c=Pos_Gen1.begin(); c!=Pos_Gen1.end(); ++c){
719
New_Pos_Table.ValPointers.push_back(pair< size_t, vector<Integer>* >((*c)->sort_deg,&((*c)->values)));
720
pos_gen1_size++;
721
}
722
}
723
724
if (!New_Negative_Irred.empty()) {
725
Negative_Depot.reduce_by(New_Negative_Irred);
726
check_range_list(New_Negative_Irred);
727
Negative_Irred.merge_by_val(New_Negative_Irred,Neg_Gen1);
728
typename list<Candidate<Integer>* >::iterator c;
729
for(c=Neg_Gen1.begin(); c!=Neg_Gen1.end(); ++c){
730
New_Neg_Table.ValPointers.push_back(pair< size_t, vector<Integer>* >((*c)->sort_deg,&((*c)->values)));
731
neg_gen1_size++;
732
}
733
}
734
735
CandidateTable<Integer> Help(true,hyp_counter);
736
737
for(int k=0;k<omp_get_max_threads();++k){
738
Help=New_Pos_Table;
739
Pos_Table[k].ValPointers.splice(Pos_Table[k].ValPointers.end(),Help.ValPointers);
740
Help=New_Neg_Table;
741
Neg_Table[k].ValPointers.splice(Neg_Table[k].ValPointers.end(),Help.ValPointers);
742
Help=New_Neutr_Table;
743
Neutr_Table[k].ValPointers.splice(Neutr_Table[k].ValPointers.end(),Help.ValPointers);
744
}
745
746
} // while(not_done)
747
748
if (verbose) {
749
verboseOutput()<<"Final sizes: Pos " << pos_gen0_size << " Neg " << neg_gen0_size << " Neutral " << Neutral_Irred.size() <<endl;
750
}
751
752
Intermediate_HB.clear();
753
Intermediate_HB.Candidates.splice(Intermediate_HB.Candidates.begin(),Positive_Irred.Candidates);
754
Intermediate_HB.Candidates.splice(Intermediate_HB.Candidates.end(),Neutral_Irred.Candidates);
755
Intermediate_HB.sort_by_val();
756
}
757
758
//---------------------------------------------------------------------------
759
760
template<typename Integer>
761
Matrix<Integer> Cone_Dual_Mode<Integer>::cut_with_halfspace(const size_t& hyp_counter, const Matrix<Integer>& BasisMaxSubspace){
762
INTERRUPT_COMPUTATION_BY_EXCEPTION
763
764
size_t i,rank_subspace=BasisMaxSubspace.nr_of_rows();
765
766
vector <Integer> restriction,lin_form=SupportHyperplanes[hyp_counter],old_lin_subspace_half;
767
bool lifting=false;
768
Matrix<Integer> New_BasisMaxSubspace=BasisMaxSubspace; // the new maximal subspace is the intersection of the old with the new haperplane
769
if (rank_subspace!=0) {
770
restriction=BasisMaxSubspace.MxV(lin_form); // the restriction of the new linear form to Max_Subspace
771
for (i = 0; i <rank_subspace; i++)
772
if (restriction[i]!=0)
773
break;
774
if (i!=rank_subspace) { // the new hyperplane does not contain the intersection of the previous hyperplanes
775
// so we must intersect the new hyperplane and Max_Subspace
776
lifting=true;
777
778
Matrix<Integer> M(1,rank_subspace); // this is the restriction of the new linear form to Max_Subspace
779
M[0]=restriction; // encoded as a matrix
780
781
size_t dummy_rank;
782
Matrix<Integer> NewBasisOldMaxSubspace=M.AlmostHermite(dummy_rank).transpose(); // compute kernel of restriction and complementary subspace
783
784
Matrix<Integer> NewBasisOldMaxSubspaceAmbient=NewBasisOldMaxSubspace.multiplication(BasisMaxSubspace);
785
// in coordinates of the ambient space
786
787
old_lin_subspace_half=NewBasisOldMaxSubspaceAmbient[0];
788
789
// old_lin_subspace_half refers to the fact that the complementary space is subdivided into
790
// two halfspaces generated by old_lin_subspace_half and -old_lin_subspace_half (taken care of in cut_with_halfspace_hilbert_basis)
791
792
Matrix<Integer> temp(rank_subspace-1,dim);
793
for(size_t k=1;k<rank_subspace;++k)
794
temp[k-1]=NewBasisOldMaxSubspaceAmbient[k];
795
New_BasisMaxSubspace=temp;
796
}
797
}
798
bool pointed=(BasisMaxSubspace.nr_of_rows()==0);
799
800
cut_with_halfspace_hilbert_basis(hyp_counter, lifting,old_lin_subspace_half,pointed);
801
802
return New_BasisMaxSubspace;
803
}
804
805
//---------------------------------------------------------------------------
806
807
template<typename Integer>
808
void Cone_Dual_Mode<Integer>::hilbert_basis_dual(){
809
810
truncate = inhomogeneous || do_only_Deg1_Elements;
811
812
if(dim==0)
813
return;
814
815
if (verbose==true) {
816
verboseOutput()<<"************************************************************\n";
817
verboseOutput()<<"computing Hilbert basis";
818
if(truncate)
819
verboseOutput() << " (truncated)";
820
verboseOutput() << " ..." << endl;
821
}
822
823
if(Generators.nr_of_rows()!=ExtremeRaysInd.size()){
824
throw FatalException("Mismatch of extreme rays and generators in cone dual mode. THIS SHOULD NOT HAPPEN.");
825
}
826
827
size_t hyp_counter; // current hyperplane
828
for (hyp_counter = 0; hyp_counter < nr_sh; hyp_counter++) {
829
BasisMaxSubspace=cut_with_halfspace(hyp_counter,BasisMaxSubspace);
830
}
831
832
if (ExtremeRaysInd.size() > 0) { // implies that we have transformed everything to a pointed full-dimensional cone
833
// must produce the relevant support hyperplanes from the generators
834
// since the Hilbert basis may have been truncated
835
vector<Integer> test(SupportHyperplanes.nr_of_rows());
836
vector<key_t> key;
837
vector<key_t> relevant_sh;
838
size_t realdim=Generators.rank();
839
for(key_t h=0;h<SupportHyperplanes.nr_of_rows();++h){
840
841
INTERRUPT_COMPUTATION_BY_EXCEPTION
842
843
key.clear();
844
vector<Integer> test=Generators.MxV(SupportHyperplanes[h]);
845
for(key_t i=0;i<test.size();++i)
846
if(test[i]==0)
847
key.push_back(i);
848
if (key.size() >= realdim-1 && Generators.submatrix(key).rank() >= realdim-1)
849
relevant_sh.push_back(h);
850
}
851
SupportHyperplanes = SupportHyperplanes.submatrix(relevant_sh);
852
}
853
if (!truncate && ExtremeRaysInd.size()==0){ // no precomputed generators
854
extreme_rays_rank();
855
relevant_support_hyperplanes();
856
ExtremeRayList.clear();
857
}
858
859
/* if(verbose)
860
verboseOutput() << "matches = " << counter << endl << "avoided = " << counter1 << endl <<
861
"comparisons = " << redcounter << endl << "comp/match " << (float) redcounter/(float) counter << endl;
862
// verboseOutput() << "matches = " << counter << endl << "avoided = " << counter1 << endl; // << "add avoided " << counter2 << endl;
863
*/
864
865
Intermediate_HB.extract(Hilbert_Basis);
866
867
if(verbose) {
868
verboseOutput() << "Hilbert basis ";
869
if(truncate)
870
verboseOutput() << "(truncated) ";
871
verboseOutput() << Hilbert_Basis.size() << endl;
872
}
873
if(SupportHyperplanes.nr_of_rows()>0 && inhomogeneous)
874
v_make_prime(SupportHyperplanes[0]); // it could be that the truncation was not coprime
875
}
876
877
//---------------------------------------------------------------------------
878
879
template<typename Integer>
880
void Cone_Dual_Mode<Integer>::extreme_rays_rank(){
881
if (verbose) {
882
verboseOutput() << "Find extreme rays" << endl;
883
}
884
size_t quotient_dim=dim-BasisMaxSubspace.nr_of_rows();
885
886
typename list < Candidate <Integer> >::iterator c;
887
vector <key_t> zero_list;
888
size_t i,k;
889
for (c=Intermediate_HB.Candidates.begin(); c!=Intermediate_HB.Candidates.end(); ++c){
890
891
INTERRUPT_COMPUTATION_BY_EXCEPTION
892
893
zero_list.clear();
894
for (i = 0; i < nr_sh; i++) {
895
if(c->values[i]==0) {
896
zero_list.push_back(i);
897
}
898
}
899
k=zero_list.size();
900
if (k>=quotient_dim-1) {
901
902
// Matrix<Integer> Test=SupportHyperplanes.submatrix(zero_list);
903
if (SupportHyperplanes.rank_submatrix(zero_list)>=quotient_dim-1) {
904
ExtremeRayList.push_back(&(*c));
905
}
906
}
907
}
908
size_t s = ExtremeRayList.size();
909
// cout << "nr extreme " << s << endl;
910
Generators = Matrix<Integer>(s,dim);
911
912
typename list< Candidate<Integer>* >::const_iterator l;
913
for (i=0, l=ExtremeRayList.begin(); l != ExtremeRayList.end(); ++l, ++i) {
914
Generators[i]= (*l)->cand;
915
}
916
ExtremeRaysInd=vector<bool>(s,true);
917
}
918
919
//---------------------------------------------------------------------------
920
921
template<typename Integer>
922
void Cone_Dual_Mode<Integer>::relevant_support_hyperplanes(){
923
if (verbose) {
924
verboseOutput() << "Find relevant support hyperplanes" << endl;
925
}
926
typename list<Candidate<Integer>* >::iterator gen_it;
927
size_t i,k,k1;
928
929
// size_t realdim = Generators.rank();
930
931
vector<vector<bool> > ind(nr_sh,vector<bool>(ExtremeRayList.size(),false));
932
vector<bool> relevant(nr_sh,true);
933
934
for (i = 0; i < nr_sh; ++i) {
935
936
INTERRUPT_COMPUTATION_BY_EXCEPTION
937
938
k = 0; k1=0;
939
for (gen_it = ExtremeRayList.begin(); gen_it != ExtremeRayList.end(); ++gen_it, ++k) {
940
if ((*gen_it)->values[i]==0) {
941
ind[i][k]=true;
942
k1++;
943
}
944
}
945
if (/* k1<realdim-1 || */ k1==Generators.nr_of_rows()) { // discard everything that vanishes on the cone
946
relevant[i]=false;
947
}
948
}
949
maximal_subsets(ind,relevant);
950
SupportHyperplanes = SupportHyperplanes.submatrix(relevant);
951
}
952
953
//---------------------------------------------------------------------------
954
955
template<typename Integer>
956
void Cone_Dual_Mode<Integer>::to_sublattice(const Sublattice_Representation<Integer>& SR) {
957
assert(SR.getDim() == dim);
958
959
if(SR.IsIdentity())
960
return;
961
962
dim = SR.getRank();
963
SupportHyperplanes = SR.to_sublattice_dual(SupportHyperplanes);
964
typename list<vector<Integer> >::iterator it;
965
vector<Integer> tmp;
966
967
Generators = SR.to_sublattice(Generators);
968
BasisMaxSubspace=SR.to_sublattice(BasisMaxSubspace);
969
970
for (it = Hilbert_Basis.begin(); it != Hilbert_Basis.end(); ) {
971
tmp = SR.to_sublattice(*it);
972
it = Hilbert_Basis.erase(it);
973
Hilbert_Basis.insert(it,tmp);
974
}
975
}
976
977
} //end namespace libnormaliz
978
979