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
#ifdef NMZ_COCOA
2
/*
3
* nmzIntegrate
4
* Copyright (C) 2012-2014 Winfried Bruns, Christof Soeger
5
* This program is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* (at your option) any later version.
9
*
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
14
*
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*
18
* As an exception, when this program is distributed through (i) the App Store
19
* by Apple Inc.; (ii) the Mac App Store by Apple Inc.; or (iii) Google Play
20
* by Google Inc., then that store may impose any digital rights management,
21
* device limits and/or redistribution restrictions that are required by its
22
* terms of service.
23
*/
24
25
#include <fstream>
26
#include <sstream>
27
#include<string>
28
29
#include "libnormaliz/nmz_integrate.h"
30
#include "libnormaliz/cone.h"
31
#include "libnormaliz/vector_operations.h"
32
#include "libnormaliz/map_operations.h"
33
34
using namespace CoCoA;
35
36
#include <boost/dynamic_bitset.hpp>
37
38
#include "../libnormaliz/my_omp.h"
39
40
namespace libnormaliz {
41
42
43
BigRat IntegralUnitSimpl(const RingElem& F, const SparsePolyRing& P, const vector<BigInt>& Factorial,
44
const vector<BigInt>& factQuot, const long& rank){
45
46
// SparsePolyRing P=owner(F);
47
long dim=NumIndets(P);
48
vector<long> v(dim);
49
50
SparsePolyIter mon=BeginIter(F); // go over the given polynomial
51
map<vector<long>,RingElem> orderedMons; // will take the ordered exponent vectors
52
map<vector<long>,RingElem>::iterator ord_mon;
53
54
for (; !IsEnded(mon); ++mon){
55
exponents(v,PP(mon)); // this function gives the exponent vector back as v
56
sort(v.begin()+1,v.begin()+rank+1);
57
ord_mon=orderedMons.find(v); // insert into map or add coefficient
58
if(ord_mon!=orderedMons.end()){
59
ord_mon->second+=coeff(mon);
60
}
61
else{
62
orderedMons.insert(pair<vector<long>,RingElem>(v,coeff(mon)));
63
}
64
}
65
66
67
long deg;
68
BigInt facProd,I;
69
I=0;
70
for(ord_mon=orderedMons.begin();ord_mon!=orderedMons.end();++ord_mon){
71
deg=0;
72
v=ord_mon->first;
73
IsInteger(facProd,ord_mon->second); // start with coefficient and multipliy by Factorials
74
for(long i=1;i<=rank;++i){
75
deg+=v[i];
76
facProd*=Factorial[v[i]];
77
}
78
I+=facProd*factQuot[deg+rank-1];// maxFact/Factorial[deg+rank-1];
79
}
80
81
BigRat Irat;
82
Irat=I;
83
return(Irat/Factorial[Factorial.size()-1]);
84
}
85
86
BigRat substituteAndIntegrate(const ourFactorization& FF,const vector<vector<long> >& A,
87
const vector<long>& degrees, const SparsePolyRing& R, const vector<BigInt>& Factorial,
88
const vector<BigInt>& factQuot,const BigInt& lcmDegs){
89
// we need F to define the ring
90
// applies linar substitution y --> y*(lcmDegs*A/degrees) to all factors in FF
91
// where row A[i] is divided by degrees[i]
92
// After substitution the polynomial is integrated over the unit simplex
93
// and the integral is returned
94
95
96
size_t i;
97
size_t m=A.size();
98
long rank=(long) m; // we prefer rank to be of type long
99
vector<RingElem> v(m,zero(R));
100
101
BigInt quot;
102
for(i=0;i<m;i++){
103
quot=lcmDegs/degrees[i];
104
v[i]=indets(R)[i+1]*quot;
105
}
106
vector<RingElem> w=VxM(v,A);
107
vector<RingElem> w1(w.size()+1,zero(R));
108
w1[0]=RingElem(R,lcmDegs);
109
for(i=1;i<w1.size();++i) // we have to shift w since the (i+1)st variable
110
w1[i]=w[i-1]; // corresponds to coordinate i (counted from 0)
111
112
113
// RingHom phi=PolyAlgebraHom(R,R,w1);
114
115
RingElem G1(zero(R));
116
list<RingElem> sortedFactors;
117
for(i=0;i<FF.myFactors.size();++i){
118
// G1=phi(FF.myFactors[i]);
119
G1=mySubstitution(FF.myFactors[i],w1);
120
for(int nn=0;nn<FF.myMultiplicities[i];++nn)
121
sortedFactors.push_back(G1);
122
}
123
124
list<RingElem>::iterator sf;
125
sortedFactors.sort(compareLength);
126
127
RingElem G(one(R));
128
129
for(sf=sortedFactors.begin();sf!=sortedFactors.end();++sf)
130
G*=*sf;
131
132
// verboseOutput() << "Evaluating integral over unit simplex" << endl;
133
// boost::dynamic_bitset<> dummyInd;
134
// vector<long> dummyDeg(degrees.size(),1);
135
return(IntegralUnitSimpl(G,R,Factorial,factQuot,rank)); // orderExpos(G,dummyDeg,dummyInd,false)
136
}
137
138
template<typename Integer>
139
void readGens(Cone<Integer>& C, vector<vector<long> >& gens, const vector<long>& grading, bool check_ascending){
140
// get from C for nmz_integrate functions
141
142
size_t i,j;
143
size_t nrows, ncols;
144
nrows=C.getNrGenerators();
145
ncols=C.getEmbeddingDim();
146
gens.resize(nrows);
147
for(i=0;i<nrows;++i)
148
gens[i].resize(ncols);
149
150
for(i=0; i<nrows; i++){
151
for(j=0; j<ncols; j++) {
152
convert(gens[i],C.getGenerators()[i]);
153
}
154
if(check_ascending){
155
long degree,prevDegree=1;
156
degree=v_scalar_product(gens[i],grading);
157
if(degree<prevDegree){
158
throw FatalException( " Degrees of generators not weakly ascending!");
159
}
160
prevDegree=degree;
161
}
162
}
163
}
164
165
bool exists_file(string name_in){
166
//n check whether file name_in exists
167
168
//b string name_in="nmzIntegrate";
169
const char* file_in=name_in.c_str();
170
171
struct stat fileStat;
172
if(stat(file_in,&fileStat) < 0){
173
return(false);
174
}
175
return(true);
176
}
177
178
void testPolynomial(const string& poly_as_string,long dim){
179
180
GlobalManager CoCoAFoundations;
181
182
string dummy=poly_as_string;
183
SparsePolyRing R=NewPolyRing_DMPI(RingQQ(),dim+1,lex);
184
RingElem the_only_factor= ReadExpr(R, dummy); // there is only one
185
// verboseOutput() << "PPPPPPPPPPPPP " << the_only_factor << endl;
186
vector<RingElem> V=homogComps(the_only_factor);
187
188
}
189
190
191
template<typename Integer>
192
void integrate(Cone<Integer>& C, const bool do_virt_mult) {
193
GlobalManager CoCoAFoundations;
194
195
try{
196
197
#ifndef NCATCH
198
std::exception_ptr tmp_exception;
199
#endif
200
201
long dim=C.getEmbeddingDim();
202
// testPolynomial(C.getIntData().getPolynomial(),dim);
203
204
bool verbose_INTsave=verbose_INT;
205
verbose_INT=C.get_verbose();
206
207
long i;
208
209
if (verbose_INT) {
210
verboseOutput() << "==========================================================" << endl;
211
verboseOutput() << "Integration" << endl;
212
verboseOutput() << "==========================================================" << endl << endl;
213
}
214
215
vector<long> grading;
216
convert(grading,C.getGrading());
217
long gradingDenom;
218
convert(gradingDenom,C.getGradingDenom());
219
long rank=C.getRank();
220
221
vector<vector<long> > gens;
222
readGens(C,gens,grading,false);
223
if(verbose_INT)
224
verboseOutput() << "Generators read" << endl;
225
226
BigInt lcmDegs(1);
227
for(size_t i=0;i<gens.size();++i){
228
long deg=v_scalar_product(gens[i],grading);
229
lcmDegs=lcm(lcmDegs,deg);
230
}
231
232
233
SparsePolyRing R=NewPolyRing_DMPI(RingQQ(),dim+1,lex);
234
SparsePolyRing RZZ=NewPolyRing_DMPI(RingZZ(),PPM(R)); // same indets and ordering as R
235
vector<RingElem> primeFactors;
236
vector<RingElem> primeFactorsNonhom;
237
vector<long> multiplicities;
238
RingElem remainingFactor(one(R));
239
240
INTERRUPT_COMPUTATION_BY_EXCEPTION
241
242
bool homogeneous;
243
RingElem F=processInputPolynomial(C.getIntData().getPolynomial(),R,RZZ,primeFactors, primeFactorsNonhom,
244
multiplicities,remainingFactor,homogeneous,do_virt_mult);
245
246
C.getIntData().setDegreeOfPolynomial(deg(F));
247
248
vector<BigInt> Factorial(deg(F)+dim); // precomputed values
249
for(i=0;i<deg(F)+dim;++i)
250
Factorial[i]=factorial(i);
251
252
vector<BigInt> factQuot(deg(F)+dim); // precomputed values
253
for(i=0;i<deg(F)+dim;++i)
254
factQuot[i]=Factorial[Factorial.size()-1]/Factorial[i];
255
256
ourFactorization FF(primeFactors,multiplicities,remainingFactor); // assembels the data
257
ourFactorization FFNonhom(primeFactorsNonhom,multiplicities,remainingFactor); // for output
258
259
long nf=FF.myFactors.size();
260
if(verbose_INT){
261
verboseOutput() <<"Factorization" << endl; // we show the factorization so that the user can check
262
for(i=0;i<nf;++i)
263
verboseOutput() << FFNonhom.myFactors[i] << " mult " << FF.myMultiplicities[i] << endl;
264
verboseOutput() << "Remaining factor " << FF.myRemainingFactor << endl << endl;
265
}
266
267
size_t tri_size=C.getTriangulation().size();
268
size_t k_start=0, k_end=tri_size;
269
270
bool pseudo_par=false;
271
size_t block_nr;
272
if(false){ // exists_file("block.nr")
273
size_t block_size=2000000;
274
pseudo_par=true;
275
string name_in="block.nr";
276
const char* file_in=name_in.c_str();
277
ifstream in;
278
in.open(file_in,ifstream::in);
279
in >> block_nr;
280
if(in.fail())
281
throw FatalException("File block.nr corrupted");
282
in.close();
283
k_start=(block_nr-1)*block_size;
284
k_end=min(k_start+block_size,tri_size);
285
286
for(size_t k=1;k<tri_size;++k)
287
if(!(C.getTriangulation()[k-1].first<C.getTriangulation()[k].first))
288
throw FatalException("Triangulation not ordered");
289
}
290
291
for(size_t k=0;k<tri_size;++k)
292
for(size_t j=1;j<C.getTriangulation()[k].first.size();++j)
293
if(!(C.getTriangulation()[k].first[j-1]<C.getTriangulation()[k].first[j]))
294
throw FatalException("Key in triangulation not ordered");
295
296
if(verbose_INT)
297
verboseOutput() << "Triangulation is ordered" << endl;
298
299
size_t eval_size;
300
if(k_start>=k_end)
301
eval_size=0;
302
else
303
eval_size=k_end-k_start;
304
305
if(verbose_INT){
306
if(pseudo_par){
307
verboseOutput() << "********************************************" << endl;
308
verboseOutput() << "Parallel block " << block_nr << endl;
309
}
310
verboseOutput() << "********************************************" << endl;
311
verboseOutput() << eval_size <<" simplicial cones to be evaluated" << endl;
312
verboseOutput() << "********************************************" << endl;
313
}
314
315
size_t progress_step=10;
316
if(tri_size >= 1000000)
317
progress_step=100;
318
319
size_t nrSimplDone=0;
320
321
vector<BigRat> I_thread(omp_get_max_threads());
322
for(size_t i=0; i< I_thread.size();++i)
323
I_thread[i]=0;
324
325
bool skip_remaining=false;
326
327
#pragma omp parallel private(i)
328
{
329
330
long det, rank=C.getTriangulation()[0].first.size();
331
vector<long> degrees(rank);
332
vector<vector<long> > A(rank);
333
BigRat ISimpl; // integral over a simplex
334
BigInt prodDeg; // product of the degrees of the generators
335
RingElem h(zero(R));
336
337
#pragma omp for schedule(dynamic)
338
for(size_t k=k_start;k<k_end;++k){
339
340
if(skip_remaining)
341
continue;
342
343
#ifndef NCATCH
344
try {
345
#endif
346
347
INTERRUPT_COMPUTATION_BY_EXCEPTION
348
349
convert(det,C.getTriangulation()[k].second);
350
for(i=0;i<rank;++i) // select submatrix defined by key
351
A[i]=gens[C.getTriangulation()[k].first[i]];
352
353
degrees=MxV(A,grading);
354
prodDeg=1;
355
for(i=0;i<rank;++i){
356
degrees[i]/=gradingDenom;
357
prodDeg*=degrees[i];
358
}
359
360
// h=homogeneousLinearSubstitutionFL(FF,A,degrees,F);
361
ISimpl=(det*substituteAndIntegrate(FF,A,degrees,RZZ,Factorial,factQuot,lcmDegs))/prodDeg;
362
I_thread[omp_get_thread_num()]+=ISimpl;
363
364
// a little bit of progress report
365
if ((++nrSimplDone)%progress_step==0 && verbose_INT)
366
#pragma omp critical(PROGRESS)
367
verboseOutput() << nrSimplDone << " simplicial cones done" << endl;
368
369
#ifndef NCATCH
370
} catch(const std::exception& ) {
371
tmp_exception = std::current_exception();
372
skip_remaining = true;
373
#pragma omp flush(skip_remaining)
374
}
375
#endif
376
377
} // triang
378
379
} // parallel
380
#ifndef NCATCH
381
if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);
382
#endif
383
384
BigRat I; // accumulates the integral
385
I=0;
386
for(size_t i=0; i< I_thread.size();++i)
387
I+=I_thread[i];
388
389
390
I/=power(lcmDegs,deg(F));
391
BigRat RFrat;
392
IsRational(RFrat,remainingFactor); // from RingQQ to BigRat
393
I*=RFrat;
394
395
string result="Integral";
396
if(do_virt_mult)
397
result="Virtual multiplicity";
398
399
BigRat VM=I;
400
401
if(do_virt_mult){
402
VM*=factorial(deg(F)+rank-1);
403
C.getIntData().setVirtualMultiplicity(mpq(VM));
404
}
405
else
406
C.getIntData().setIntegral(mpq(I));
407
408
if(verbose_INT){
409
verboseOutput() << "********************************************" << endl;
410
verboseOutput() << result << " is " << endl << VM << endl;
411
verboseOutput() << "********************************************" << endl;
412
}
413
414
if(pseudo_par){
415
string name_out="block.nr";
416
const char* file=name_out.c_str();
417
ofstream out(file);
418
out << block_nr+1 << endl;
419
out.close();
420
421
name_out="block_"+to_string((size_t) block_nr)+".mult";
422
file=name_out.c_str();
423
ofstream out_1(file);
424
out_1 << block_nr << ", "<< VM << "," << endl;
425
out_1.close();
426
427
/* string chmod="chmod a+w "+name_out;
428
const char* exec=chmod.c_str();
429
system(exec);
430
431
string mail_str="mail [email protected] < "+name_out;
432
exec=name_out.c_str();
433
system(exec);*/
434
435
/*mail_str="mail [email protected] < "+name_out;
436
exec=name_out.c_str();
437
system(exec);*/
438
}
439
440
verbose_INT=verbose_INTsave;
441
} // try
442
catch (const CoCoA::ErrorInfo& err)
443
{
444
cerr << "***ERROR*** UNCAUGHT CoCoA error";
445
ANNOUNCE(cerr, err);
446
447
throw NmzCoCoAException("");
448
}
449
}
450
451
CyclRatFunct evaluateFaceClasses(const vector<vector<CyclRatFunct> >& GFP,
452
map<vector<long>,RingElem>& faceClasses){
453
// computes the generating rational functions
454
// for the denominator classes collected from proper faces and returns the sum
455
456
SparsePolyRing R=owner(faceClasses.begin()->second);
457
CyclRatFunct H(zero(R));
458
// vector<CyclRatFunct> h(omp_get_max_threads(),CyclRatFunct(zero(R)));
459
// vector<CyclRatFunct> h(1,CyclRatFunct(zero(R)));
460
461
long mapsize=faceClasses.size();
462
if(verbose_INT){
463
verboseOutput() << "--------------------------------------------" << endl;
464
verboseOutput() << "Evaluating " << mapsize <<" face classes" << endl;
465
verboseOutput() << "--------------------------------------------" << endl;
466
}
467
#pragma omp parallel
468
{
469
470
map<vector<long>,RingElem>::iterator den=faceClasses.begin();
471
long mpos=0;
472
CyclRatFunct h(zero(R));
473
474
#pragma omp for schedule(dynamic)
475
for(long dc=0;dc<mapsize;++dc){
476
for(;mpos<dc;++mpos,++den);
477
for(;mpos>dc;--mpos,--den);
478
// verboseOutput() << "mpos " << mpos << endl;
479
480
h = genFunct(GFP,den->second,den->first);
481
h.simplifyCRF();
482
if(verbose_INT){
483
#pragma omp critical(VERBOSE)
484
{
485
verboseOutput() << "Class ";
486
for(size_t i=0;i<den->first.size();++i)
487
verboseOutput() << den->first[i] << " ";
488
verboseOutput() << "NumTerms " << NumTerms(den->second) << endl;
489
490
// verboseOutput() << "input " << den->second << endl;
491
}
492
}
493
494
// h.showCoprimeCRF();
495
#pragma omp critical(ADDCLASSES)
496
H.addCRF(h);
497
}
498
499
} // parallel
500
faceClasses.clear();
501
H.simplifyCRF();
502
return(H);
503
}
504
505
struct denomClassData{
506
vector<long> degrees;
507
size_t simplDue;
508
size_t simplDone;
509
};
510
511
CyclRatFunct evaluateDenomClass(const vector<vector<CyclRatFunct> >& GFP,
512
pair<denomClassData,vector<RingElem> >& denomClass){
513
// computes the generating rational function
514
// for a denominator class and returns it
515
516
SparsePolyRing R=owner(denomClass.second[0]);
517
518
if(verbose_INT){
519
#pragma omp critical(PROGRESS)
520
{
521
verboseOutput() << "--------------------------------------------" << endl;
522
verboseOutput() << "Evaluating denom class ";
523
for(size_t i=0;i<denomClass.first.degrees.size();++i)
524
verboseOutput() << denomClass.first.degrees[i] << " ";
525
verboseOutput() << "NumTerms " << NumTerms(denomClass.second[0]) << endl;
526
// verboseOutput() << denomClass.second << endl;
527
verboseOutput() << "--------------------------------------------" << endl;
528
}
529
}
530
531
CyclRatFunct h(zero(R));
532
h = genFunct(GFP,denomClass.second[0],denomClass.first.degrees);
533
534
denomClass.second[0]=0; // to save memory
535
h.simplifyCRF();
536
return(h);
537
}
538
539
void transferFacePolys(deque<pair<vector<long>,RingElem> >& facePolysThread,
540
map<vector<long>,RingElem>& faceClasses){
541
542
543
// verboseOutput() << "In Transfer " << facePolysThread.size() << endl;
544
map<vector<long>,RingElem>::iterator den_found;
545
for(size_t i=0;i<facePolysThread.size();++i){
546
den_found=faceClasses.find(facePolysThread[i].first);
547
if(den_found!=faceClasses.end()){
548
den_found->second+=facePolysThread[i].second;
549
}
550
else{
551
faceClasses.insert(facePolysThread[i]);
552
if(verbose_INT){
553
#pragma omp critical(VERBOSE)
554
{
555
verboseOutput() << "New face class " << faceClasses.size() << " degrees ";
556
for(size_t j=0;j<facePolysThread[i].first.size();++j)
557
verboseOutput() << facePolysThread[i].first[j] << " ";
558
verboseOutput() << endl << flush;
559
}
560
}
561
} // else
562
}
563
facePolysThread.clear();
564
}
565
566
libnormaliz::HilbertSeries nmzHilbertSeries(const CyclRatFunct& H, mpz_class& commonDen)
567
{
568
569
size_t i;
570
vector<RingElem> HCoeff0=ourCoeffs(H.num,0); // we must convert the coefficients
571
BigInt commonDenBI(1); // and find the common denominator
572
vector<BigRat> HCoeff1(HCoeff0.size());
573
for(i=0;i<HCoeff0.size();++i){
574
IsRational(HCoeff1[i],HCoeff0[i]); // to BigRat
575
commonDenBI=lcm(den(HCoeff1[i]),commonDenBI);
576
}
577
578
commonDen=mpz(commonDenBI); // convert it to mpz_class
579
580
BigInt HC2;
581
vector<mpz_class> HCoeff3(HCoeff0.size());
582
for(i=0;i<HCoeff1.size();++i){
583
HC2=num(HCoeff1[i]*commonDenBI); // to BigInt
584
HCoeff3[i]=mpz(HC2); // to mpz_class
585
}
586
587
vector<long> denomDeg=denom2degrees(H.denom);
588
libnormaliz::HilbertSeries HS(HCoeff3,count_in_map<long, long>(denomDeg));
589
HS.simplify();
590
return(HS);
591
}
592
593
bool compareDegrees(const STANLEYDATA_int& A, const STANLEYDATA_int& B){
594
595
return(A.degrees < B.degrees);
596
}
597
598
bool compareFaces(const SIMPLINEXDATA_INT& A, const SIMPLINEXDATA_INT& B){
599
600
return(A.card > B.card);
601
}
602
603
void prepare_inclusion_exclusion_simpl(const STANLEYDATA_int& S,
604
const vector<pair<boost::dynamic_bitset<>, long> >& inExCollect,
605
vector<SIMPLINEXDATA_INT>& inExSimplData) {
606
607
size_t dim=S.key.size();
608
vector<key_type> key=S.key;
609
for(size_t i=0;i<dim;++i)
610
key[i];
611
612
boost::dynamic_bitset<> intersection(dim), Excluded(dim);
613
614
Excluded.set();
615
for(size_t j=0;j<dim;++j) // enough to test the first offset (coming from the zero vector)
616
if(S.offsets[0][j]==0)
617
Excluded.reset(j);
618
619
vector<pair<boost::dynamic_bitset<>, long> >::const_iterator F;
620
map<boost::dynamic_bitset<>, long> inExSimpl; // local version of nExCollect
621
map<boost::dynamic_bitset<>, long>::iterator G;
622
623
for(F=inExCollect.begin();F!=inExCollect.end();++F){
624
// verboseOutput() << "F " << F->first << endl;
625
bool still_active=true;
626
for(size_t i=0;i<dim;++i)
627
if(Excluded[i] && !F->first.test(key[i])){
628
still_active=false;
629
break;
630
}
631
if(!still_active)
632
continue;
633
intersection.reset();
634
for(size_t i=0;i<dim;++i){
635
if(F->first.test(key[i]))
636
intersection.set(i);
637
}
638
G=inExSimpl.find(intersection);
639
if(G!=inExSimpl.end())
640
G->second+=F->second;
641
else
642
inExSimpl.insert(pair<boost::dynamic_bitset<> , long>(intersection,F->second));
643
}
644
645
SIMPLINEXDATA_INT HilbData;
646
inExSimplData.clear();
647
vector<long> degrees;
648
649
for(G=inExSimpl.begin();G!=inExSimpl.end();++G){
650
if(G->second!=0){
651
HilbData.GenInFace=G->first;
652
HilbData.mult=G->second;
653
HilbData.card=G->first.count();
654
degrees.clear();
655
for(size_t j=0;j<dim;++j)
656
if(G->first.test(j))
657
degrees.push_back(S.degrees[j]);
658
HilbData.degrees=degrees;
659
HilbData.denom=degrees2denom(degrees);
660
inExSimplData.push_back(HilbData);
661
}
662
}
663
664
sort(inExSimplData.begin(),inExSimplData.end(),compareFaces);
665
666
/* for(size_t i=0;i<inExSimplData.size();++i)
667
verboseOutput() << inExSimplData[i].GenInFace << " ** " << inExSimplData[i].card << " || " << inExSimplData[i].mult << " ++ "<< inExSimplData[i].denom << endl;
668
verboseOutput() << "InEx prepared" << endl; */
669
670
}
671
672
template<typename Integer>
673
void readInEx(Cone<Integer>& C, vector<pair<boost::dynamic_bitset<>, long> >& inExCollect, const size_t nrGen){
674
675
size_t inExSize=C.getInclusionExclusionData().size(), keySize;
676
long mult;
677
boost::dynamic_bitset<> indicator(nrGen);
678
for(size_t i=0;i<inExSize;++i){
679
keySize=C.getInclusionExclusionData()[i].first.size();
680
indicator.reset();
681
for(size_t j=0;j<keySize;++j){
682
indicator.set(C.getInclusionExclusionData()[i].first[j]);
683
}
684
mult=C.getInclusionExclusionData()[i].second;
685
inExCollect.push_back(pair<boost::dynamic_bitset<>, long>(indicator,mult));
686
}
687
}
688
689
template<typename Integer>
690
void readDecInEx(Cone<Integer>& C, const long& dim, /* list<STANLEYDATA_int_INT>& StanleyDec, */
691
vector<pair<boost::dynamic_bitset<>, long> >& inExCollect, const size_t nrGen){
692
// rads Stanley decomposition and InExSata from C
693
694
if(C.isComputed(ConeProperty::InclusionExclusionData)){
695
readInEx(C, inExCollect,nrGen);
696
}
697
698
// STANLEYDATA_int_INT newSimpl;
699
// ong i=0;
700
// newSimpl.key.resize(dim);
701
702
long test;
703
704
auto SD=C.getStanleyDec_mutable().begin();
705
auto SD_end=C.getStanleyDec_mutable().end();
706
707
for(;SD!=SD_end;++SD){
708
709
// swap(newSimpl.key,SD->key);
710
test=-1;
711
for(long i=0;i<dim;++i){
712
if(SD->key[i]<=test){
713
throw FatalException("Key of simplicial cone not ascending or out of range");
714
}
715
test=SD->key[i];
716
}
717
718
/* swap(newSimpl.offsets,SD->offsets);
719
StanleyDec.push_back(newSimpl);
720
SD=C.getStanleyDec_mutable().erase(SD);*/
721
}
722
// C.resetStanleyDec();
723
}
724
725
template<typename Integer>
726
void generalizedEhrhartSeries(Cone<Integer>& C){
727
GlobalManager CoCoAFoundations;
728
729
try{
730
731
bool verbose_INTsave=verbose_INT;
732
verbose_INT=C.get_verbose();
733
734
if(verbose_INT){
735
verboseOutput() << "==========================================================" << endl;
736
verboseOutput() << "Weighted Ehrhart series " << endl;
737
verboseOutput() << "==========================================================" << endl << endl;
738
}
739
740
long i,j;
741
742
vector<long> grading;
743
convert(grading,C.getGrading());
744
long gradingDenom;
745
convert(gradingDenom,C.getGradingDenom());
746
long rank=C.getRank();
747
long dim=C.getEmbeddingDim();
748
749
// processing the input polynomial
750
751
SparsePolyRing R=NewPolyRing_DMPI(RingQQ(),dim+1,lex);
752
SparsePolyRing RZZ=NewPolyRing_DMPI(RingZZ(),PPM(R)); // same indets and ordering as R
753
const RingElem& t=indets(RZZ)[0];
754
vector<RingElem> primeFactors;
755
vector<RingElem> primeFactorsNonhom;
756
vector<long> multiplicities;
757
RingElem remainingFactor(one(R));
758
759
INTERRUPT_COMPUTATION_BY_EXCEPTION
760
761
bool homogeneous;
762
RingElem F=processInputPolynomial(C.getIntData().getPolynomial(),R,RZZ,primeFactors, primeFactorsNonhom,
763
multiplicities,remainingFactor,homogeneous,false);
764
765
C.getIntData().setDegreeOfPolynomial(deg(F));
766
767
vector<BigInt> Factorial(deg(F)+dim); // precomputed values
768
for(i=0;i<deg(F)+dim;++i)
769
Factorial[i]=factorial(i);
770
771
ourFactorization FF(primeFactors,multiplicities,remainingFactor); // assembeles the data
772
ourFactorization FFNonhom(primeFactorsNonhom,multiplicities,remainingFactor); // for output
773
774
long nf=FF.myFactors.size();
775
if(verbose_INT){
776
verboseOutput() <<"Factorization" << endl; // we show the factorization so that the user can check
777
for(i=0;i<nf;++i)
778
verboseOutput() << FFNonhom.myFactors[i] << " mult " << FF.myMultiplicities[i] << endl;
779
verboseOutput() << "Remaining factor " << FF.myRemainingFactor << endl << endl;
780
}
781
// inputpolynomial processed
782
783
if(rank==0){
784
vector<RingElem> compsF= homogComps(F);
785
CyclRatFunct HRat(compsF[0]);
786
mpz_class commonDen; // common denominator of coefficients of numerator of H
787
libnormaliz::HilbertSeries HS(nmzHilbertSeries(HRat,commonDen));
788
C.getIntData().setWeightedEhrhartSeries(make_pair(HS,commonDen));
789
C.getIntData().computeWeightedEhrhartQuasiPolynomial();
790
C.getIntData().setVirtualMultiplicity(0);
791
return;
792
}
793
794
795
vector<vector<long> > gens;
796
readGens(C,gens,grading,true);
797
if(verbose_INT)
798
verboseOutput() << "Generators read" << endl;
799
long maxDegGen=v_scalar_product(gens[gens.size()-1],grading)/gradingDenom;
800
801
INTERRUPT_COMPUTATION_BY_EXCEPTION
802
803
// list<STANLEYDATA_int_INT> StanleyDec;
804
vector<pair<boost::dynamic_bitset<>, long> > inExCollect;
805
readDecInEx(C,rank,inExCollect,gens.size());
806
if(verbose_INT)
807
verboseOutput() << "Stanley decomposition (and in/ex data) read" << endl;
808
809
list<STANLEYDATA_int>& StanleyDec=C.getStanleyDec_mutable();
810
811
size_t dec_size=StanleyDec.size();
812
813
// Now we sort the Stanley decomposition by denominator class (= degree class)
814
815
auto S = StanleyDec.begin();
816
817
vector<long> degrees(rank);
818
vector<vector<long> > A(rank);
819
820
// prepare sorting by computing degrees of generators
821
822
BigInt lcmDets(1); // to become the lcm of all dets of simplicial cones
823
824
for(;S!=StanleyDec.end();++S){
825
826
INTERRUPT_COMPUTATION_BY_EXCEPTION
827
828
for(i=0;i<rank;++i) // select submatrix defined by key
829
A[i]=gens[S->key[i]];
830
degrees=MxV(A,grading);
831
for(i=0;i<rank;++i)
832
degrees[i]/=gradingDenom; // must be divisible
833
S->degrees=degrees;
834
lcmDets=lcm(lcmDets,S->offsets.nr_of_rows());
835
}
836
837
if(verbose_INT)
838
verboseOutput() << "lcm(dets)=" << lcmDets << endl;
839
840
StanleyDec.sort(compareDegrees);
841
842
if(verbose_INT)
843
verboseOutput() << "Stanley decomposition sorted" << endl;
844
845
vector<pair<denomClassData, vector<RingElem> > > denomClasses;
846
denomClassData denomClass;
847
vector<RingElem> ZeroVectRingElem;
848
for(int j=0;j<omp_get_max_threads();++j)
849
ZeroVectRingElem.push_back(zero(RZZ));
850
851
map<vector<long>,RingElem> faceClasses; // denominator classes for the faces
852
// contrary to denomClasses these cannot be sorted beforehand
853
854
vector<deque<pair<vector<long>,RingElem> > > facePolys(omp_get_max_threads()); // intermediate storage
855
bool evaluationActive=false;
856
857
// we now make class 0 to get started
858
S=StanleyDec.begin();
859
denomClass.degrees=S->degrees; // put degrees in class
860
denomClass.simplDone=0;
861
denomClass.simplDue=1; // already one simplex to be done
862
denomClasses.push_back(pair<denomClassData,vector<RingElem> >(denomClass,ZeroVectRingElem));
863
size_t dc=0;
864
S->classNr=dc; // assignment of class 0 to first simpl in sorted order
865
866
auto prevS = StanleyDec.begin();
867
868
for(++S;S!=StanleyDec.end();++S,++prevS){
869
if(S->degrees==prevS->degrees){ // compare to predecessor
870
S->classNr=dc; // assign class to simplex
871
denomClasses[dc].first.simplDue++; // number of simplices in class ++
872
}
873
else{
874
denomClass.degrees=S->degrees; // make new class
875
denomClass.simplDone=0;
876
denomClass.simplDue=1;
877
denomClasses.push_back(pair<denomClassData,vector<RingElem> >(denomClass,ZeroVectRingElem));
878
dc++;
879
S->classNr=dc;
880
}
881
}
882
883
if(verbose_INT)
884
verboseOutput() << denomClasses.size() << " denominator classes built" << endl;
885
886
887
vector<vector<CyclRatFunct> > GFP; // we calculate the table of generating functions
888
vector<CyclRatFunct> DummyCRFVect; // for\sum i^n t^ki vor various values of k and n
889
CyclRatFunct DummyCRF(zero(RZZ));
890
for(j=0;j<=deg(F);++j)
891
DummyCRFVect.push_back(DummyCRF);
892
for(i=0;i<=maxDegGen;++i){
893
GFP.push_back(DummyCRFVect);
894
for(j=0;j<=deg(F);++j)
895
GFP[i][j]=genFunctPower1(RZZ,i,j);
896
}
897
898
CyclRatFunct H(zero(RZZ)); // accumulates the series
899
900
if(verbose_INT){
901
verboseOutput() << "********************************************" << endl;
902
verboseOutput() << dec_size <<" simplicial cones to be evaluated" << endl;
903
verboseOutput() << "********************************************" << endl;
904
}
905
906
size_t progress_step=10;
907
if(dec_size >= 1000000)
908
progress_step=100;
909
910
size_t nrSimplDone=0;
911
912
#ifndef NCATCH
913
std::exception_ptr tmp_exception;
914
#endif
915
916
bool skip_remaining=false;
917
int omp_start_level=omp_get_level();
918
919
#pragma omp parallel private(i)
920
{
921
922
long degree_b;
923
long det;
924
bool evaluateClass;
925
vector<long> degrees;
926
vector<vector<long> > A(rank);
927
auto S=StanleyDec.begin();
928
929
RingElem h(zero(RZZ)); // for use in a simplex
930
CyclRatFunct HClass(zero(RZZ)); // for single class
931
932
size_t s,spos=0;
933
#pragma omp for schedule(dynamic)
934
for(s=0;s<dec_size;++s){
935
936
if(skip_remaining)
937
continue;
938
939
for(;spos<s;++spos,++S);
940
for(;spos>s;--spos,--S);
941
942
#ifndef NCATCH
943
try {
944
#endif
945
946
INTERRUPT_COMPUTATION_BY_EXCEPTION
947
948
int tn;
949
if(omp_get_level()==omp_start_level)
950
tn=0;
951
else
952
tn = omp_get_ancestor_thread_num(omp_start_level+1);
953
954
det=S->offsets.nr_of_rows();
955
degrees=S->degrees;
956
957
for(i=0;i<rank;++i) // select submatrix defined by key
958
A[i]=gens[S->key[i]];
959
960
vector<SIMPLINEXDATA_INT> inExSimplData;
961
if(inExCollect.size()!=0)
962
prepare_inclusion_exclusion_simpl(*S,inExCollect,inExSimplData);
963
964
h=0;
965
long iS=S->offsets.nr_of_rows(); // compute numerator for simplex being processed
966
for(i=0;i<iS;++i){
967
degree_b=v_scalar_product(degrees,S->offsets[i]);
968
degree_b/=det;
969
h+=power(t,degree_b)*affineLinearSubstitutionFL(FF,A,S->offsets[i],det,RZZ,degrees,lcmDets,
970
inExSimplData, facePolys[tn]);
971
}
972
973
evaluateClass=false; // necessary to evaluate class only once
974
975
// #pragma omp critical (ADDTOCLASS)
976
{
977
denomClasses[S->classNr].second[tn]+=h;
978
#pragma omp critical (ADDTOCLASS)
979
{
980
denomClasses[S->classNr].first.simplDone++;
981
982
if(denomClasses[S->classNr].first.simplDone==denomClasses[S->classNr].first.simplDue)
983
evaluateClass=true;
984
}
985
}
986
if(evaluateClass)
987
{
988
989
for(int j=1;j<omp_get_max_threads();++j){
990
denomClasses[S->classNr].second[0]+=denomClasses[S->classNr].second[j];
991
denomClasses[S->classNr].second[j]=0;
992
}
993
994
// denomClasses[S->classNr].second=0; // <-------------------------------------
995
HClass=evaluateDenomClass(GFP,denomClasses[S->classNr]);
996
#pragma omp critical(ACCUMULATE)
997
{
998
H.addCRF(HClass);
999
}
1000
1001
}
1002
1003
if(!evaluationActive && facePolys[tn].size() >= 20){
1004
#pragma omp critical(FACEPOLYS)
1005
{
1006
evaluationActive=true;
1007
transferFacePolys(facePolys[tn],faceClasses);
1008
evaluationActive=false;
1009
}
1010
}
1011
1012
#pragma omp critical(PROGRESS) // a little bit of progress report
1013
{
1014
if((++nrSimplDone)%progress_step==0 && verbose_INT)
1015
verboseOutput() << nrSimplDone << " simplicial cones done " << endl; // nrActiveFaces-nrActiveFacesOld << " faces done" << endl;
1016
// nrActiveFacesOld=nrActiveFaces;
1017
}
1018
1019
#ifndef NCATCH
1020
} catch(const std::exception& ) {
1021
tmp_exception = std::current_exception();
1022
skip_remaining=true;
1023
#pragma omp flush(skip_remaining)
1024
}
1025
#endif
1026
1027
} // Stanley dec
1028
1029
} // parallel
1030
1031
#ifndef NCATCH
1032
if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);
1033
#endif
1034
1035
// collect the contribution of proper fases from inclusion/exclusion as far as not done yet
1036
1037
for(int i=0;i<omp_get_max_threads();++i)
1038
transferFacePolys(facePolys[i],faceClasses);
1039
1040
if(!faceClasses.empty())
1041
H.addCRF(evaluateFaceClasses(GFP,faceClasses));
1042
1043
// now we must return to rational coefficients
1044
1045
CyclRatFunct HRat(zero(R));
1046
HRat.denom=H.denom;
1047
HRat.num=makeQQCoeff(H.num,R);
1048
1049
HRat.num*=FF.myRemainingFactor;
1050
HRat.num/=power(lcmDets,deg(F));
1051
1052
HRat.showCoprimeCRF();
1053
1054
mpz_class commonDen; // common denominator of coefficients of numerator of H
1055
libnormaliz::HilbertSeries HS(nmzHilbertSeries(HRat,commonDen));
1056
HS.set_nr_coeff_quasipol(C.getIntData().getWeightedEhrhartSeries().first.get_nr_coeff_quasipol());
1057
HS.set_period_bounded(C.getIntData().getWeightedEhrhartSeries().first.get_period_bounded());
1058
1059
C.getIntData().setWeightedEhrhartSeries(make_pair(HS,commonDen));
1060
1061
C.getIntData().computeWeightedEhrhartQuasiPolynomial();
1062
1063
if(C.getIntData().isWeightedEhrhartQuasiPolynomialComputed()){
1064
mpq_class genMultQ;
1065
long deg=C.getIntData().getWeightedEhrhartQuasiPolynomial()[0].size()-1;
1066
long virtDeg=C.getRank()+C.getIntData().getDegreeOfPolynomial()-1;
1067
if(deg==virtDeg)
1068
genMultQ=C.getIntData().getWeightedEhrhartQuasiPolynomial()[0][virtDeg];
1069
genMultQ*=ourFactorial(virtDeg);
1070
genMultQ/=C.getIntData().getWeightedEhrhartQuasiPolynomialDenom();
1071
C.getIntData().setVirtualMultiplicity(genMultQ);
1072
}
1073
1074
verbose_INT=verbose_INTsave;
1075
1076
return;
1077
} // try
1078
catch (const CoCoA::ErrorInfo& err)
1079
{
1080
cerr << "***ERROR*** UNCAUGHT CoCoA error";
1081
ANNOUNCE(cerr, err);
1082
1083
throw NmzCoCoAException("");
1084
}
1085
}
1086
1087
#ifndef NMZ_MIC_OFFLOAD //offload with long is not supported
1088
template void integrate(Cone<long>& C, const bool do_virt_mult);
1089
#endif // NMZ_MIC_OFFLOAD
1090
template void integrate(Cone<long long>& C, const bool do_virt_mult);
1091
template void integrate(Cone<mpz_class>& C, const bool do_virt_mult);
1092
1093
#ifndef NMZ_MIC_OFFLOAD //offload with long is not supported
1094
template void generalizedEhrhartSeries<long>(Cone<long>& C);
1095
#endif // NMZ_MIC_OFFLOAD
1096
template void generalizedEhrhartSeries<long long>(Cone<long long>& C);
1097
template void generalizedEhrhartSeries<mpz_class>(Cone<mpz_class>& C);
1098
1099
1100
1101
} // namespace libnormaliz
1102
1103
#endif //NMZ_COCOA
1104
1105