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

563644 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 "nmz_integrate.h"
30
31
using namespace CoCoA;
32
33
#include <boost/dynamic_bitset.hpp>
34
35
#include "../libnormaliz/my_omp.h"
36
37
using namespace std;
38
39
namespace libnormaliz {
40
41
ourFactorization::ourFactorization(const vector<RingElem>& myFactors,
42
const vector<long>& myMultiplicities, const RingElem& myRemainingFactor){
43
44
this->myFactors=myFactors;
45
this->myMultiplicities=myMultiplicities;
46
this->myRemainingFactor=myRemainingFactor;
47
}
48
49
ourFactorization::ourFactorization(const factorization<RingElem>& FF){
50
51
ourFactorization(FF.myFactors(),FF.myMultiplicities(),FF.myRemainingFactor());
52
53
}
54
55
RingElem binomial(const RingElem& f, long k)
56
// computes binomial coefficient (f choose k)
57
{
58
const SparsePolyRing& P=owner(f);
59
RingElem g(P);
60
g=1;
61
for(int i=0;i<k;i++)
62
g*=(f-i)/(i+1);
63
return(g);
64
}
65
66
RingElem ascFact(const RingElem& f, long k)
67
// computes (f+1)*...*(f+k)
68
{
69
const SparsePolyRing& P=owner(f);
70
RingElem g(P);
71
g=1;
72
for(int i=0;i<k;i++)
73
g*=(f+i+1);
74
return(g);
75
}
76
77
RingElem descFact(const RingElem& f, long k)
78
// computes f*(f-1)*...*(f-k+1)
79
{
80
const SparsePolyRing& P=owner(f);
81
RingElem g(P);
82
g=1;
83
for(int i=0;i<k;i++)
84
g*=(f-i);
85
return(g);
86
}
87
88
bool compareLength(const RingElem& p, const RingElem& q){
89
return(NumTerms(p)>NumTerms(q));
90
}
91
92
vector<RingElem> ourCoeffs(const RingElem& F, const long j){
93
// our version of expanding a poly nomial wrt to indeterminate j
94
// The return value is the vector of coefficients of x[j]^i
95
vector<RingElem> c;
96
const SparsePolyRing& P=owner(F);
97
RingElem x=indets(P)[j];
98
if(F==0){
99
c.push_back(zero(P));
100
return(c);
101
}
102
103
vector<long> v(NumIndets(P));
104
long k,cs;
105
106
SparsePolyIter i=BeginIter(F);
107
for (; !IsEnded(i); ++i){
108
exponents(v,PP(i));
109
k=v[j];
110
cs=c.size();
111
if(k>cs-1)
112
c.resize(k+1,zero(P));
113
v[j]=0;
114
// c[k]+=monomial(P,coeff(i),v);
115
PushBack(c[k],coeff(i),v);
116
}
117
return(c);
118
}
119
120
RingElem mySubstitution(const RingElem& F, const vector<RingElem>& w){
121
122
const SparsePolyRing& R=owner(F);
123
RingElem G(zero(R));
124
RingElem H(one(R));
125
vector<long> v(NumIndets(R));
126
vector<long> Z(NumIndets(R));
127
128
SparsePolyIter i=BeginIter(F);
129
for (; !IsEnded(i); ++i){
130
exponents(v,PP(i));
131
H=zero(R);
132
PushBack(H,coeff(i),Z);
133
for(size_t j=0;j<v.size();++j)
134
H*=power(w[j],v[j]);
135
G+=H;
136
}
137
return G;
138
}
139
140
vector<long> MxV(const vector<vector<long> >& M, vector<long> V){
141
// matrix*vector
142
vector<long> P(M.size());
143
for(size_t i=0;i< M.size();++i){
144
long s=0;
145
for(size_t j=0;j<V.size();++j)
146
s+=M[i][j]*V[j];
147
P[i]=s;
148
}
149
return(P);
150
}
151
152
vector<RingElem> VxM(const vector<RingElem>& V, const vector<vector<long> >& M){
153
// vector*matrix
154
const SparsePolyRing& R=owner(V[0]);
155
RingElem s(zero(R));
156
vector<RingElem> P(M[0].size(),zero(R));
157
for(size_t j=0;j<M[0].size();++j){
158
s=0;
159
for(size_t i=0;i<M.size();++i)
160
s+=V[i]*M[i][j];
161
P[j]=s;
162
}
163
return(P);
164
}
165
166
167
/*
168
RingElem affineLinearSubstitution(const RingElem& F,const vector<vector<long> >& A,
169
const vector<long>& b, const long& denom){
170
// NOT IN USE
171
size_t i;
172
const SparsePolyRing& R=owner(F);
173
size_t m=A.size();
174
// long n=A[0].size();
175
vector<RingElem> v(m,zero(R));
176
RingElem g(zero(R));
177
178
for(i=0;i<m;i++)
179
{
180
g=b[i];
181
g=g/denom;
182
v[i]=g+indets(R)[i+1];
183
}
184
vector<RingElem> w=VxM(v,A);
185
vector<RingElem> w1(w.size()+1,zero(R));
186
w1[0]=indets(R)[0];
187
for(i=1;i<w1.size();++i)
188
w1[i]=w[i-1];
189
190
RingHom phi=PolyAlgebraHom(R,R,w1);
191
RingElem G=phi(F);
192
return(G);
193
}
194
*/
195
196
bool DDD=false;
197
198
vector<long> shiftVars(const vector<long>& v, const vector<long>& key){
199
// selects components of v and reorders them according to key
200
vector<long> w(v.size(),0);
201
for(size_t i=0;i<key.size();++i){
202
w[i]=v[key[i]];
203
}
204
return(w);
205
}
206
207
void makeLocalDegreesAndKey(const boost::dynamic_bitset<>& indicator,const vector<long>& degrees, vector<long>& localDeg,vector<long>& key){
208
209
localDeg.clear();
210
key.clear();
211
key.push_back(0);
212
for(size_t i=0;i<indicator.size();++i)
213
if(indicator.test(i))
214
key.push_back(i+1);
215
for(size_t i=0;i<key.size()-1;++i)
216
localDeg.push_back(degrees[key[i+1]-1]);
217
}
218
219
void makeStartEnd(const vector<long>& localDeg, vector<long>& St, vector<long>& End){
220
221
vector<long> denom=degrees2denom(localDeg); // first we must find the blocks of equal degree
222
if(denom.size()==0)
223
return;
224
St.push_back(1);
225
for(size_t i=0;i<denom.size();++i)
226
if(denom[i]!=0){
227
End.push_back(St[St.size()-1]+denom[i]-1);
228
if(i<denom.size()-1)
229
St.push_back(End[End.size()-1]+1);
230
}
231
/* if(St.size()!=End.size()){
232
for (size_t i=0;i<denom.size(); ++i){
233
verboseOutput() << denom.size() << endl;
234
verboseOutput() << denom[i] << " ";
235
verboseOutput() << endl;
236
}
237
}*/
238
}
239
240
vector<long> orderExposInner(vector<long>& vin, const vector<long>& St, vector<long>& End){
241
242
vector<long> v=vin;
243
long p,s,pend,pst;
244
bool ordered;
245
if(St.size()!=End.size()){
246
verboseOutput() << St.size() << " " << End.size() << " " << vin.size() << endl;
247
verboseOutput() << St[0] << endl;
248
for (size_t i=0;i<vin.size(); ++i){
249
verboseOutput() << vin[i] << " ";
250
}
251
verboseOutput() << endl;
252
assert(false);
253
}
254
for(size_t j=0;j<St.size();++j){ // now we go over the blocks
255
pst=St[j];
256
pend=End[j];
257
while(1){
258
ordered=true;
259
for(p=pst;p<pend;++p){
260
if(v[p]<v[p+1]){
261
ordered=false;
262
s=v[p];
263
v[p]=v[p+1];
264
v[p+1]=s;
265
}
266
}
267
if(ordered)
268
break;
269
pend--;
270
}
271
}
272
return(v);
273
}
274
275
RingElem orderExpos(const RingElem& F, const vector<long>& degrees, const boost::dynamic_bitset<>& indicator, bool compactify){
276
// orders the exponent vectors v of the terms of F
277
// the exponents v[i] and v[j], i < j, are swapped if
278
// (1) degrees[i]==degrees[j] and (2) v[i] < v[j]
279
// so that the exponents are descending in each degree block
280
// the ordered exponent vectors are inserted into a map
281
// and their coefficients are added
282
// at the end the polynomial is rebuilt from the map
283
// If compactify==true, the exponents will be shifted to the left in order to keep the correspondence
284
// of variables to degrees
285
// compactification not used at present (occurs only in restrictToFaces)
286
287
const SparsePolyRing& P=owner(F);
288
vector<long> v(NumIndets(P));
289
vector<long> key,localDeg;
290
key.reserve(v.size()+1);
291
localDeg.reserve(degrees.size()+1);
292
293
if(compactify){
294
makeLocalDegreesAndKey(indicator,degrees,localDeg,key);
295
}
296
else{
297
localDeg=degrees;
298
}
299
300
vector<long> St,End;
301
makeStartEnd(localDeg,St,End);
302
303
// now the main job
304
305
map<vector<long>,RingElem> orderedMons; // will take the ordered exponent vectors
306
map<vector<long>,RingElem>::iterator ord_mon;
307
308
SparsePolyIter mon=BeginIter(F); // go over the given polynomial
309
for (; !IsEnded(mon); ++mon){
310
exponents(v,PP(mon)); // this function gives the exponent vector back as v
311
if(compactify)
312
v=shiftVars(v,key);
313
v=orderExposInner(v,St,End);
314
ord_mon=orderedMons.find(v); // insert into map or add coefficient
315
if(ord_mon!=orderedMons.end()){
316
ord_mon->second+=coeff(mon);
317
}
318
else{
319
orderedMons.insert(pair<vector<long>,RingElem>(v,coeff(mon)));
320
}
321
}
322
323
// now we must reconstruct the polynomial
324
// we use that the natural order of vectors in C++ STL is inverse
325
// to lex. Therefore push_front
326
327
RingElem r(zero(P));
328
//JAA verboseOutput() << "Loop start " << orderedMons.size() << endl;
329
//JAA size_t counter=0;
330
for(ord_mon=orderedMons.begin();ord_mon!=orderedMons.end();++ord_mon){
331
//JAA verboseOutput() << counter++ << ord_mon->first << endl;
332
//JAA try {
333
PushFront(r,ord_mon->second,ord_mon->first);
334
//JAA }
335
//JAA catch(const std::exception& exc){verboseOutput() << "Caught exception: " << exc.what() << endl;}
336
}
337
//JAA verboseOutput() << "Loop end" << endl;
338
return(r);
339
}
340
341
342
void restrictToFaces(const RingElem& G,RingElem& GOrder, vector<RingElem>& GRest,const vector<long> degrees, const vector<SIMPLINEXDATA_INT>& inExSimplData){
343
// Computesd the restrictions of G to the faces in inclusion-exclusion.
344
// All terms are simultaneously compactified and exponentwise ordered
345
// Polynomials returned in GRest
346
// Ordering is also applied to G itself, returned in GOrder
347
// Note: degrees are given for the full simplex. Therefore "local" degreees must be made
348
// (depend only on face and not on offset, but generation here is cheap)
349
350
const SparsePolyRing& P=owner(G);
351
352
vector<long> v(NumIndets(P));
353
vector<long> w(NumIndets(P));
354
vector<long> localDeg;
355
localDeg.reserve(v.size());
356
size_t dim=NumIndets(P)-1;
357
358
// first we make the facewise data that are needed for the compactification and otrdering
359
// of exponent vectors
360
vector<vector<long> > St(inExSimplData.size()),End(inExSimplData.size()),key(inExSimplData.size());
361
vector<long> active;
362
for(size_t i=0;i<inExSimplData.size();++i)
363
if(!inExSimplData[i].done){
364
active.push_back(i);
365
makeLocalDegreesAndKey(inExSimplData[i].GenInFace ,degrees,localDeg,key[i]);
366
makeStartEnd(localDeg,St[i],End[i]);
367
}
368
369
// now the same for the full simplex (localDeg=degrees)
370
boost::dynamic_bitset<> fullSimpl(dim);
371
fullSimpl.set();
372
vector<long> StSimpl,EndSimpl;
373
makeStartEnd(degrees,StSimpl,EndSimpl);
374
375
vector<map<vector<long>,RingElem> > orderedMons(inExSimplData.size()); // will take the ordered exponent vectors
376
map<vector<long>,RingElem> orderedMonsSimpl;
377
map<vector<long>,RingElem>::iterator ord_mon;
378
379
380
boost::dynamic_bitset<> indicator(dim);
381
382
// now we go over the terms of G
383
SparsePolyIter term=BeginIter(G);
384
//PPMonoid TT = PPM(owner(G));
385
for (; !IsEnded(term); ++term){
386
//PPMonoidElem mon(PP(term));
387
exponents(v,PP(term));
388
w=v;
389
indicator.reset();
390
for(size_t j=0;j<dim;++j)
391
if(v[j+1]!=0) // we must add 1 since the 0-th indeterminate is irrelevant here
392
indicator.set(j);
393
for(size_t i=0;i<active.size();++i){
394
int j=active[i];
395
if(indicator.is_subset_of(inExSimplData[j].GenInFace)){
396
w=shiftVars(v,key[j]);
397
w=orderExposInner(w,St[j],End[j]);
398
// w=shiftVars(v,key[j]);
399
ord_mon=orderedMons[j].find(w); // insert into map or add coefficient
400
if(ord_mon!=orderedMons[j].end()){
401
ord_mon->second+=coeff(term);
402
}
403
else{
404
orderedMons[j].insert(pair<vector<long>,RingElem>(w,coeff(term)));
405
}
406
}
407
} // for i
408
409
v=orderExposInner(v,StSimpl,EndSimpl);
410
ord_mon=orderedMonsSimpl.find(v); // insert into map or add coefficient
411
if(ord_mon!=orderedMonsSimpl.end()){
412
ord_mon->second+=coeff(term);
413
}
414
else{
415
orderedMonsSimpl.insert(pair<vector<long>,RingElem>(v,coeff(term)));
416
}
417
} // loop over term
418
419
// now we must make the resulting polynomials from the maps
420
421
for(size_t i=0;i<active.size();++i){
422
int j=active[i];
423
for(ord_mon=orderedMons[j].begin();ord_mon!=orderedMons[j].end();++ord_mon){
424
PushFront(GRest[j],ord_mon->second,ord_mon->first);
425
}
426
// verboseOutput() << "GRest[j] " << j << " " << NumTerms(GRest[j]) << endl;
427
}
428
429
for(ord_mon=orderedMonsSimpl.begin();ord_mon!=orderedMonsSimpl.end();++ord_mon){
430
PushFront(GOrder,ord_mon->second,ord_mon->first);
431
}
432
433
}
434
435
long nrActiveFaces=0;
436
long nrActiveFacesOld=0;
437
438
void all_contained_faces(const RingElem& G, RingElem& GOrder,const vector<long>& degrees,
439
boost::dynamic_bitset<>& indicator, long Deg,vector<SIMPLINEXDATA_INT>& inExSimplData,
440
deque<pair<vector<long>,RingElem> >& facePolysThread){
441
442
const SparsePolyRing& R=owner(G);
443
vector<RingElem> GRest;
444
// size_t dim=indicator.size();
445
for(size_t i=0;i<inExSimplData.size();++i){
446
GRest.push_back(zero(R));
447
448
if(!indicator.is_subset_of(inExSimplData[i].GenInFace))
449
inExSimplData[i].done=true; // done if face cannot contribute to result for this offset
450
else
451
inExSimplData[i].done=false; // not done otherwise
452
}
453
restrictToFaces(G,GOrder,GRest,degrees,inExSimplData);
454
455
for(size_t j=0;j<inExSimplData.size();++j){
456
if(inExSimplData[j].done)
457
continue;
458
#pragma omp atomic
459
nrActiveFaces++;
460
// verboseOutput() << "Push back " << NumTerms(GRest[j]);
461
GRest[j]=power(indets(R)[0],Deg)*inExSimplData[j].mult*GRest[j]; // shift by degree of offset amd multiply by mult of face
462
facePolysThread.push_back(pair<vector<long>,RingElem>(inExSimplData[j].degrees,GRest[j]));
463
// verboseOutput() << " Now " << facePolysThread.size() << endl;
464
}
465
}
466
467
RingElem affineLinearSubstitutionFL(const ourFactorization& FF,const vector<vector<long> >& A,
468
const vector<long>& b, const long& denom, const SparsePolyRing& R, const vector<long>& degrees, const BigInt& lcmDets,
469
vector<SIMPLINEXDATA_INT>& inExSimplData,deque<pair<vector<long>,RingElem> >& facePolysThread){
470
// applies linar substitution y --> lcmDets*A(y+b/denom) to all factors in FF
471
// and returns the product of the modified factorsafter ordering the exponent vectors
472
473
size_t i;
474
size_t m=A.size();
475
size_t dim=m; // TO DO: eliminate this duplication
476
vector<RingElem> v(m,zero(R));
477
RingElem g(zero(R));
478
479
for(i=0;i<m;i++)
480
{
481
g=b[i]*(lcmDets/denom);
482
v[i]=g+lcmDets*indets(R)[i+1];
483
}
484
vector<RingElem> w=VxM(v,A);
485
vector<RingElem> w1(w.size()+1,zero(R));
486
w1[0]=RingElem(R,lcmDets);
487
for(i=1;i<w1.size();++i)
488
w1[i]=w[i-1];
489
490
// RingHom phi=PolyAlgebraHom(R,R,w1);
491
492
RingElem G1(zero(R));
493
list<RingElem> sortedFactors;
494
for(i=0;i<FF.myFactors.size();++i){
495
// G1=phi(FF.myFactors[i]);
496
G1=mySubstitution(FF.myFactors[i],w1);
497
for(int nn=0;nn<FF.myMultiplicities[i];++nn)
498
sortedFactors.push_back(G1);
499
}
500
501
list<RingElem>::iterator sf;
502
sortedFactors.sort(compareLength);
503
504
RingElem G(one(R));
505
506
for(sf=sortedFactors.begin();sf!=sortedFactors.end();++sf)
507
G*=*sf;
508
509
if(inExSimplData.size()==0){ // not really necesary, but a slight shortcut
510
boost::dynamic_bitset<> dummyInd;
511
return(orderExpos(G,degrees,dummyInd,false));
512
}
513
514
// if(inExSimplData.size()!=0){
515
long Deg=0;
516
boost::dynamic_bitset<> indicator(dim); // indicates the non-zero components of b
517
indicator.reset();
518
for(size_t i=0;i<dim;++i)
519
if(b[i]!=0){
520
indicator.set(i);
521
Deg+=degrees[i]*b[i];
522
}
523
Deg/=denom;
524
RingElem Gorder(zero(R));
525
all_contained_faces(G,Gorder,degrees,indicator, Deg, inExSimplData,facePolysThread);
526
return(Gorder);
527
// }
528
}
529
530
531
vector<RingElem> homogComps(const RingElem& F){
532
// returns the vector of homogeneous components of F
533
// w.r.t. standard grading
534
535
const SparsePolyRing& P=owner(F);
536
long dim=NumIndets(P);
537
vector<long> v(dim);
538
vector<RingElem> c(deg(F)+1,zero(P));
539
long j,k;
540
541
//TODO there is a leading_term() function coming in cocoalib
542
//TODO maybe there will be even a "splice_leading_term"
543
SparsePolyIter i=BeginIter(F);
544
for (; !IsEnded(i); ++i){
545
exponents(v,PP(i));
546
k=0;
547
for(j=0;j<dim;j++)
548
k+=v[j];
549
PushBack(c[k],coeff(i),v);
550
}
551
return(c);
552
}
553
554
RingElem homogenize(const RingElem& F){
555
// homogenizes F wrt the zeroth variable and returns the
556
// homogenized polynomial
557
558
SparsePolyRing P=owner(F);
559
int d=deg(F);
560
vector<RingElem> c(d+1,zero(P));
561
c=homogComps(F);
562
RingElem h(zero(P));
563
for(int i=0;i<=d;++i)
564
h+=c[i]*power(indets(P)[0],d-i);
565
return(h);
566
}
567
568
RingElem makeZZCoeff(const RingElem& F, const SparsePolyRing& RZZ){
569
// F is a polynomial over RingQQ with integral coefficients
570
// This function converts it into a polynomial over RingZZ
571
572
SparsePolyIter mon=BeginIter(F); // go over the given polynomial
573
RingElem G(zero(RZZ));
574
for (; !IsEnded(mon); ++mon){
575
PushBack(G,num(coeff(mon)),PP(mon));
576
}
577
return(G);
578
}
579
580
581
RingElem makeQQCoeff(const RingElem& F, const SparsePolyRing& R){
582
// F is a polynomial over RingZZ
583
// This function converts it into a polynomial over RingQQ
584
SparsePolyIter mon=BeginIter(F); // go over the given polynomial
585
RingElem G(zero(R));
586
for (; !IsEnded(mon); ++mon){
587
PushBack(G,RingElem(RingQQ(),coeff(mon)),PP(mon));
588
}
589
return(G);
590
}
591
592
RingElem processInputPolynomial(const string& poly_as_string, const SparsePolyRing& R, const SparsePolyRing& RZZ,
593
vector<RingElem>& resPrimeFactors, vector<RingElem>& resPrimeFactorsNonhom, vector<long>& resMultiplicities,
594
RingElem& remainingFactor, bool& homogeneous,const bool& do_leadCoeff){
595
// "res" stands for "result"
596
// resPrimeFactors are homogenized, the "nonhom" come from the original polynomial
597
598
long i,j;
599
string dummy=poly_as_string;
600
RingElem the_only_dactor= ReadExpr(R, dummy); // there is only one
601
vector<RingElem> factorsRead; // this is from the very first version of NmzIntegrate
602
factorsRead.push_back(the_only_dactor);
603
vector<long> multiplicities;
604
605
vector<RingElem> primeFactors; // for use in this routine
606
vector<RingElem> primeFactorsNonhom; // return results will go into the "res" parameters for output
607
608
if(verbose_INT)
609
verboseOutput() << "Polynomial read" << endl;
610
611
homogeneous=true; // we factor the polynomials read
612
for(i=0;i< (long) factorsRead.size();++i){ // and make them integral this way
613
// they must further be homogenized
614
// and converted to polynomials with ZZ
615
// coefficients (instead of inegral QQ)
616
// The homogenization is necessary to allow
617
// substitutions over ZZ
618
RingElem G(factorsRead[i]);
619
if(deg(G)==0){
620
remainingFactor*=G; // constants go into remainingFactor
621
continue; // this extra treatment would not be necessary
622
}
623
// homogeneous=(G==LF(G));
624
vector<RingElem> compsG= homogComps(G);
625
// we test for homogeneity. In case do_leadCoeff==true, polynomial
626
// is replaced by highest homogeneous component
627
if(G!=compsG[compsG.size()-1]){
628
homogeneous=false;
629
// if(!homogeneous){
630
if(verbose_INT && do_leadCoeff)
631
verboseOutput() << "Polynomial is inhomogeneous. Replacing it by highest hom. comp." << endl;
632
if(do_leadCoeff){
633
G=compsG[compsG.size()-1];
634
// G=LF(G);
635
factorsRead[i]=G; // though it may no longer be the factor read from input
636
}
637
}
638
639
factorization<RingElem> FF=factor(G); // now the factorization and transfer to integer coefficients
640
for(j=0;j< (long) FF.myFactors().size();++j){
641
primeFactorsNonhom.push_back(FF.myFactors()[j]); // these are the factors of the polynomial to be integrated
642
primeFactors.push_back(makeZZCoeff(homogenize(FF.myFactors()[j]),RZZ)); // the homogenized factors with ZZ coeff
643
multiplicities.push_back(FF.myMultiplicities()[j]); // homogenized for substitution !
644
}
645
remainingFactor*=FF.myRemainingFactor();
646
}
647
648
649
// it remains to collect multiple factors that come from different input factors
650
651
for(i=0;i< (long) primeFactors.size();++i)
652
if(primeFactors[i]!=0)
653
for(j=i+1;j< (long) primeFactors.size();++j)
654
if(primeFactors[j]!=0 && primeFactors[i]==primeFactors[j]){
655
primeFactors[j]=0;
656
multiplicities[i]++;
657
}
658
659
for(i=0;i< (long) primeFactors.size();++i) // now everything is transferred to the return parameters
660
if(primeFactors[i]!=0){
661
resPrimeFactorsNonhom.push_back(primeFactorsNonhom[i]);
662
resPrimeFactors.push_back(primeFactors[i]);
663
resMultiplicities.push_back(multiplicities[i]);
664
}
665
666
RingElem F(one(R)); //th polynomial to be integrated
667
for(i=0;i< (long) factorsRead.size();++i) // with QQ coefficients
668
F*=factorsRead[i];
669
670
return(F);
671
}
672
673
CyclRatFunct genFunct(const vector<vector<CyclRatFunct> >& GFP, const RingElem& F, const vector<long>& degrees)
674
// writes \sum_{x\in\ZZ_+^n} f(x,t) T^x
675
// under the specialization T_i --> t^g_i
676
// as a rational function in t
677
{
678
const SparsePolyRing& P=owner(F);
679
RingElem t=indets(P)[0];
680
681
CyclRatFunct s(F); // F/1
682
683
CyclRatFunct g(zero(P)),h(zero(P));
684
685
long nd=degrees.size();
686
long i,k,mg;
687
vector<RingElem> c;
688
689
for(k=1; k<=nd;k++)
690
{
691
c=ourCoeffs(s.num,k); // we split the numerator according
692
// to powers of var k
693
mg=c.size(); // max degree+1 in var k
694
695
h.set2(zero(P));
696
for(i=0;i<mg;i++) // now we replace the powers of var k
697
{ // by the corrseponding rational function,
698
// multiply, and sum the products
699
700
h.num=(1-power(t,degrees[k-1]))*h.num+GFP[degrees[k-1]][i].num*c[i];
701
h.denom=GFP[degrees[k-1]][i].denom;
702
}
703
s.num=h.num;
704
s.denom=prodDenom(s.denom,h.denom);
705
}
706
return(s);
707
}
708
709
vector<RingElem> power2ascFact(const SparsePolyRing& P, const long& k)
710
// computes the representation of the power x^n as the linear combination
711
// of (x+1)_n,...,(x+1)_0
712
// return value is the vector of coefficients (they belong to ZZ)
713
{
714
RingElem t=indets(P)[0];
715
const vector<long> ONE(NumIndets(P));
716
RingElem f(P),g(P), h(P);
717
f=power(t,k);
718
long m;
719
vector<RingElem> c(k+1,zero(P));
720
while(f!=0)
721
{
722
m=deg(f);
723
h=monomial(P,LC(f),ONE);
724
c[m]=h;
725
f-=h*ascFact(t,m);
726
}
727
return(c);
728
}
729
730
731
CyclRatFunct genFunctPower1(const SparsePolyRing& P, long k,long n)
732
// computes the generating function for
733
// \sum_j j^n (t^k)^j
734
{
735
vector<RingElem> a=power2ascFact(P,n);
736
RingElem b(P);
737
vector<long> u;
738
CyclRatFunct g(zero(P)), h(zero(P));
739
long i,s=a.size();
740
for(i=0;i<s;++i)
741
{
742
u=makeDenom(k,i+1);
743
b=a[i]*factorial(i);
744
g.set2(b,u);
745
h.addCRF(g);
746
}
747
return(h);
748
}
749
750
void CyclRatFunct::extendDenom(const vector<long>& target)
751
// extends the denominator to target
752
// by multiplying the numrerator with the remaining factor
753
{
754
RingElem t=indets(owner(num))[0];
755
long i,ns=target.size(),nf=denom.size();
756
for(i=1;i<ns;++i){
757
if(i>nf-1)
758
num*=power(1-power(t,i),(target[i]));
759
else
760
if(target[i]>denom[i])
761
num*=power(1-power(t,i),(target[i]-denom[i]));
762
}
763
denom=target;
764
}
765
766
vector<long> lcmDenom(const vector<long>& df, const vector<long>& dg){
767
// computes the lcm of ztwo denominators as used in CyclRatFunct
768
// (1-t^i and 1-t^j, i != j, are considered as coprime)
769
size_t nf=df.size(),ng=dg.size(),i;
770
size_t n=max(nf,ng);
771
vector<long> dh=df;
772
dh.resize(n);
773
for(i=1;i<n;++i)
774
if(i<ng && dh[i]<dg[i])
775
dh[i]=dg[i];
776
return(dh);
777
}
778
779
780
vector<long> prodDenom(const vector<long>& df, const vector<long>& dg){
781
// as above, but computes the profduct
782
size_t nf=df.size(),ng=dg.size(),i;
783
size_t n=max(nf,ng);
784
vector<long> dh=df;
785
dh.resize(n);
786
for(i=1;i<n;++i)
787
if(i<ng)
788
dh[i]+=dg[i];
789
return(dh);
790
}
791
792
vector<long> degrees2denom(const vector<long>& d){
793
// converts a vector of degrees to a "denominator"
794
// listing at position i the multiplicity of i in d
795
long m=0;
796
size_t i;
797
if(d.size()==0)
798
return vector<long> (0);
799
for(i=0;i<d.size();++i)
800
m=max(m,d[i]);
801
vector<long> e(m+1);
802
for(i=0;i<d.size();++i)
803
e[d[i]]++;
804
return(e);
805
}
806
807
vector<long> denom2degrees(const vector<long>& d){
808
// the converse operation
809
vector<long> denomDeg;
810
for(size_t i=0;i<d.size();++i)
811
for(long j=0;j<d[i];++j)
812
denomDeg.push_back(i);
813
return(denomDeg);
814
}
815
816
RingElem denom2poly(const SparsePolyRing& P, const vector<long>& d){
817
// converts a denominator into a real polynomial
818
// the variable for the denominator is x[0]
819
RingElem t=indets(P)[0];
820
RingElem f(one(P));
821
for(size_t i=1;i<d.size();++i)
822
f*=power(1-power(t,i),d[i]);
823
return(f);
824
}
825
826
vector<long> makeDenom(long k,long n)
827
// makes the denominator (1-t^k)^n
828
{
829
vector<long> d(k+1);
830
d[k]=n;
831
return(d);
832
}
833
834
void CyclRatFunct::addCRF(const CyclRatFunct& r){
835
// adds r to *this, r is preserved in its given form
836
CyclRatFunct s(zero(owner(num)));
837
const vector<long> lcmden(lcmDenom(denom,r.denom));
838
s=r;
839
s.extendDenom(lcmden);
840
extendDenom(lcmden);
841
num+=s.num;
842
}
843
844
void CyclRatFunct::multCRF(const CyclRatFunct& r){
845
// nmultiplies *this by r
846
num*=r.num;
847
denom=prodDenom(denom,r.denom);
848
}
849
850
void CyclRatFunct::showCRF(){
851
if(!verbose_INT)
852
return;
853
854
verboseOutput() << num << endl;
855
for(size_t i=1;i<denom.size();++i)
856
verboseOutput() << denom[i] << " ";
857
verboseOutput() << endl;
858
}
859
860
void CyclRatFunct::showCoprimeCRF(){
861
// shows *this also with coprime numerator and denominator
862
// makes only sense if only x[0] appears in the numerator (not checked)
863
864
if(!verbose_INT)
865
return;
866
867
verboseOutput() << "--------------------------------------------" << endl << endl;
868
verboseOutput() << "Given form" << endl << endl;
869
showCRF();
870
verboseOutput() << endl;
871
const SparsePolyRing& R=owner(num);
872
SparsePolyRing P=NewPolyRing_DMPI(RingQQ(),symbols("t"));
873
vector<RingElem> Im(NumIndets(R),zero(P));
874
Im[0]=indets(P)[0];
875
RingHom phi=PolyAlgebraHom(R,P,Im);
876
RingElem f(phi(num));
877
RingElem g(denom2poly(P,denom));
878
RingElem h=CoCoA::gcd(f,g);
879
f/=h;
880
g/=h;
881
verboseOutput() << "Coprime numerator (for denom with remaining factor 1)" << endl <<endl;
882
factorization<RingElem> gf=factor(g);
883
verboseOutput() << f/gf.myRemainingFactor() << endl << endl << "Factorization of denominator" << endl << endl;
884
size_t nf=gf.myFactors().size();
885
for(size_t i=0;i<nf;++i)
886
verboseOutput() << gf.myFactors()[i] << " mult " << gf.myMultiplicities()[i] << endl;
887
verboseOutput() << "--------------------------------------------" << endl;
888
889
}
890
891
void CyclRatFunct::simplifyCRF(){
892
// cancels factors 1-t^i from the denominator that appear there explicitly
893
// (and not just as factors of 1-t^j for some j)
894
895
const SparsePolyRing& R=owner(num);
896
long nd=denom.size();
897
for(long i=1;i<nd;i++)
898
{
899
while(denom[i]>0)
900
{
901
if(!IsDivisible(num,1-power(indets(R)[0],i)))
902
break;
903
num/=1-power(indets(R)[0],i);
904
denom[i]--;
905
}
906
}
907
}
908
909
void CyclRatFunct::set2(const RingElem& f, const vector<long>& d)
910
{
911
num=f;
912
denom=d;
913
}
914
915
void CyclRatFunct::set2(const RingElem& f)
916
{
917
num=f;
918
denom.resize(1,0);
919
}
920
921
CyclRatFunct::CyclRatFunct(const RingElem& c):num(c)
922
// constructor starting from a RingElem
923
// initialization necessary because RingElem has no default
924
// constructor
925
{
926
denom.resize(1,0);
927
}
928
929
CyclRatFunct::CyclRatFunct(const RingElem& c,const vector<long>& d):num(c),denom(d){
930
}
931
932
933
934
} // namespace
935
#endif //NMZ_COCOA
936