gen_fun::coefficient: new version returning ZZ
[barvinok.git] / genfun.cc
blob17fc8725fd893ef89f6525d3edcec43edaf0ddda
1 #include <iostream>
2 #include <vector>
3 #include <assert.h>
4 #include "config.h"
5 #include <barvinok/genfun.h>
6 #include <barvinok/barvinok.h>
7 #include "conversion.h"
8 #include "genfun_constructor.h"
9 #include "mat_util.h"
11 using std::cout;
12 using std::cerr;
13 using std::endl;
14 using std::pair;
15 using std::vector;
17 bool short_rat_lex_smaller_denominator::operator()(const short_rat* r1,
18 const short_rat* r2) const
20 return lex_cmp(r1->d.power, r2->d.power) < 0;
23 static void lex_order_terms(struct short_rat* rat)
25 for (int i = 0; i < rat->n.power.NumRows(); ++i) {
26 int m = i;
27 for (int j = i+1; j < rat->n.power.NumRows(); ++j)
28 if (lex_cmp(rat->n.power[j], rat->n.power[m]) < 0)
29 m = j;
30 if (m != i) {
31 vec_ZZ tmp = rat->n.power[m];
32 rat->n.power[m] = rat->n.power[i];
33 rat->n.power[i] = tmp;
34 QQ tmp_coeff = rat->n.coeff[m];
35 rat->n.coeff[m] = rat->n.coeff[i];
36 rat->n.coeff[i] = tmp_coeff;
41 short_rat::short_rat(Value c)
43 n.coeff.SetLength(1);
44 value2zz(c, n.coeff[0].n);
45 n.coeff[0].d = 1;
46 n.power.SetDims(1, 0);
47 d.power.SetDims(0, 0);
50 short_rat::short_rat(const QQ& c, const vec_ZZ& num, const mat_ZZ& den)
52 n.coeff.SetLength(1);
53 ZZ g = GCD(c.n, c.d);
54 n.coeff[0].n = c.n/g;
55 n.coeff[0].d = c.d/g;
56 n.power.SetDims(1, num.length());
57 n.power[0] = num;
58 d.power = den;
59 normalize();
62 void short_rat::normalize()
64 /* Make all powers in denominator reverse-lexico-positive */
65 for (int i = 0; i < d.power.NumRows(); ++i) {
66 int j;
67 for (j = d.power.NumCols()-1; j >= 0; --j)
68 if (d.power[i][j] != 0)
69 break;
70 assert(j >= 0);
71 if (d.power[i][j] < 0) {
72 d.power[i] = -d.power[i];
73 for (int k = 0; k < n.coeff.length(); ++k) {
74 n.coeff[k].n = -n.coeff[k].n;
75 n.power[k] += d.power[i];
80 /* Order powers in denominator */
81 lex_order_rows(d.power);
84 void short_rat::add(short_rat *r)
86 for (int i = 0; i < r->n.power.NumRows(); ++i) {
87 int len = n.coeff.length();
88 int j;
89 for (j = 0; j < len; ++j)
90 if (r->n.power[i] == n.power[j])
91 break;
92 if (j < len) {
93 n.coeff[j] += r->n.coeff[i];
94 if (n.coeff[j].n == 0) {
95 if (j < len-1) {
96 n.power[j] = n.power[len-1];
97 n.coeff[j] = n.coeff[len-1];
99 int dim = n.power.NumCols();
100 n.coeff.SetLength(len-1);
101 n.power.SetDims(len-1, dim);
103 } else {
104 int dim = n.power.NumCols();
105 n.coeff.SetLength(len+1);
106 n.power.SetDims(len+1, dim);
107 n.coeff[len] = r->n.coeff[i];
108 n.power[len] = r->n.power[i];
113 QQ short_rat::coefficient(Value* params, barvinok_options *options) const
115 unsigned nvar = d.power.NumRows();
116 unsigned nparam = d.power.NumCols();
117 Matrix *C = Matrix_Alloc(nparam + nvar, 1 + nvar + 1);
118 Value tmp;
119 value_init(tmp);
121 QQ c(0, 1);
123 for (int j = 0; j < n.coeff.length(); ++j) {
124 C->NbRows = nparam+nvar;
125 for (int r = 0; r < nparam; ++r) {
126 value_set_si(C->p[r][0], 0);
127 for (int c = 0; c < nvar; ++c) {
128 zz2value(d.power[c][r], C->p[r][1+c]);
130 zz2value(n.power[j][r], C->p[r][1+nvar]);
131 value_subtract(C->p[r][1+nvar], C->p[r][1+nvar], params[r]);
133 for (int r = 0; r < nvar; ++r) {
134 value_set_si(C->p[nparam+r][0], 1);
135 Vector_Set(&C->p[nparam+r][1], 0, nvar + 1);
136 value_set_si(C->p[nparam+r][1+r], 1);
138 Polyhedron *P = Constraints2Polyhedron(C, options->MaxRays);
139 if (emptyQ2(P)) {
140 Polyhedron_Free(P);
141 continue;
143 barvinok_count_with_options(P, &tmp, options);
144 Polyhedron_Free(P);
145 if (value_zero_p(tmp))
146 continue;
147 QQ c2(0, 1);
148 value2zz(tmp, c2.n);
149 c2 *= n.coeff[j];
150 c += c2;
152 Matrix_Free(C);
153 value_clear(tmp);
154 return c;
157 bool short_rat::reduced()
159 int dim = n.power.NumCols();
160 lex_order_terms(this);
161 if (n.power.NumRows() % 2 == 0) {
162 if (n.coeff[0].n == -n.coeff[1].n &&
163 n.coeff[0].d == n.coeff[1].d) {
164 vec_ZZ step = n.power[1] - n.power[0];
165 int k;
166 for (k = 1; k < n.power.NumRows()/2; ++k) {
167 if (n.coeff[2*k].n != -n.coeff[2*k+1].n ||
168 n.coeff[2*k].d != n.coeff[2*k+1].d)
169 break;
170 if (step != n.power[2*k+1] - n.power[2*k])
171 break;
173 if (k == n.power.NumRows()/2) {
174 for (k = 0; k < d.power.NumRows(); ++k)
175 if (d.power[k] == step)
176 break;
177 if (k < d.power.NumRows()) {
178 for (++k; k < d.power.NumRows(); ++k)
179 d.power[k-1] = d.power[k];
180 d.power.SetDims(k-1, dim);
181 for (k = 1; k < n.power.NumRows()/2; ++k) {
182 n.coeff[k] = n.coeff[2*k];
183 n.power[k] = n.power[2*k];
185 n.coeff.SetLength(k);
186 n.power.SetDims(k, dim);
187 return true;
192 return false;
195 gen_fun::gen_fun(Value c)
197 short_rat *r = new short_rat(c);
198 context = Universe_Polyhedron(0);
199 term.insert(r);
202 void gen_fun::add(const QQ& c, const vec_ZZ& num, const mat_ZZ& den)
204 if (c.n == 0)
205 return;
207 short_rat * r = new short_rat(c, num, den);
209 short_rat_list::iterator i = term.find(r);
210 while (i != term.end()) {
211 (*i)->add(r);
212 if ((*i)->n.coeff.length() == 0) {
213 delete *i;
214 term.erase(i);
215 } else if ((*i)->reduced()) {
216 delete r;
217 /* we've modified term[i], so remove it
218 * and add it back again
220 r = *i;
221 term.erase(i);
222 i = term.find(r);
223 continue;
225 delete r;
226 return;
229 term.insert(r);
232 void gen_fun::add(const QQ& c, const gen_fun *gf)
234 QQ p;
235 for (short_rat_list::iterator i = gf->term.begin(); i != gf->term.end(); ++i) {
236 for (int j = 0; j < (*i)->n.power.NumRows(); ++j) {
237 p = c;
238 p *= (*i)->n.coeff[j];
239 add(p, (*i)->n.power[j], (*i)->d.power);
244 static void split_param_compression(Matrix *CP, mat_ZZ& map, vec_ZZ& offset)
246 Matrix *T = Transpose(CP);
247 matrix2zz(T, map, T->NbRows-1, T->NbColumns-1);
248 values2zz(T->p[T->NbRows-1], offset, T->NbColumns-1);
249 Matrix_Free(T);
253 * Perform the substitution specified by CP
255 * CP is a homogeneous matrix that maps a set of "compressed parameters"
256 * to the original set of parameters.
258 * This function is applied to a gen_fun computed with the compressed parameters
259 * and adapts it to refer to the original parameters.
261 * That is, if y are the compressed parameters and x = A y + b are the original
262 * parameters, then we want the coefficient of the monomial t^y in the original
263 * generating function to be the coefficient of the monomial u^x in the resulting
264 * generating function.
265 * The original generating function has the form
267 * a t^m/(1-t^n) = a t^m + a t^{m+n} + a t^{m+2n} + ...
269 * Since each term t^y should correspond to a term u^x, with x = A y + b, we want
271 * a u^{A m + b} + a u^{A (m+n) + b} + a u^{A (m+2n) +b} + ... =
273 * = a u^{A m + b}/(1-u^{A n})
275 * Therefore, we multiply the powers m and n in both numerator and denominator by A
276 * and add b to the power in the numerator.
277 * Since the above powers are stored as row vectors m^T and n^T,
278 * we compute, say, m'^T = m^T A^T to obtain m' = A m.
280 * The pair (map, offset) contains the same information as CP.
281 * map is the transpose of the linear part of CP, while offset is the constant part.
283 void gen_fun::substitute(Matrix *CP)
285 mat_ZZ map;
286 vec_ZZ offset;
287 split_param_compression(CP, map, offset);
288 Polyhedron *C = Polyhedron_Image(context, CP, 0);
289 Polyhedron_Free(context);
290 context = C;
292 short_rat_list new_term;
293 for (short_rat_list::iterator i = term.begin(); i != term.end(); ++i) {
294 short_rat *r = (*i);
295 r->d.power *= map;
296 r->n.power *= map;
297 for (int j = 0; j < r->n.power.NumRows(); ++j)
298 r->n.power[j] += offset;
299 r->normalize();
300 new_term.insert(r);
302 term.swap(new_term);
305 struct cone {
306 int *pos;
307 vector<pair<Vector *, QQ> > vertices;
308 cone(int *pos) : pos(pos) {}
311 #ifndef HAVE_COMPRESS_PARMS
312 static Matrix *compress_parms(Matrix *M, unsigned nparam)
314 assert(0);
316 #endif
318 struct parallel_polytopes {
319 gf_base *red;
320 Polyhedron *context;
321 Matrix *Constraints;
322 Matrix *CP, *T;
323 int dim;
324 int nparam;
325 vector<cone> cones;
326 barvinok_options *options;
328 parallel_polytopes(int n, Polyhedron *context, int nparam,
329 barvinok_options *options) :
330 context(context), dim(-1), nparam(nparam),
331 options(options) {
332 red = NULL;
333 Constraints = NULL;
334 CP = NULL;
335 T = NULL;
337 bool add(const QQ& c, Polyhedron *P) {
338 int i;
340 for (i = 0; i < P->NbEq; ++i)
341 if (First_Non_Zero(P->Constraint[i]+1,
342 P->Dimension-nparam) == -1)
343 break;
344 if (i < P->NbEq)
345 return false;
347 Polyhedron *Q = remove_equalities_p(Polyhedron_Copy(P), P->Dimension-nparam,
348 NULL);
349 POL_ENSURE_VERTICES(Q);
350 if (emptyQ(Q)) {
351 Polyhedron_Free(Q);
352 return true;
355 if (Q->NbEq != 0) {
356 Polyhedron *R;
357 if (!CP) {
358 Matrix *M;
359 M = Matrix_Alloc(Q->NbEq, Q->Dimension+2);
360 Vector_Copy(Q->Constraint[0], M->p[0], Q->NbEq * (Q->Dimension+2));
361 CP = compress_parms(M, nparam);
362 T = align_matrix(CP, Q->Dimension+1);
363 Matrix_Free(M);
365 R = Polyhedron_Preimage(Q, T, options->MaxRays);
366 Polyhedron_Free(Q);
367 Q = remove_equalities_p(R, R->Dimension-nparam, NULL);
369 assert(Q->NbEq == 0);
371 if (First_Non_Zero(Q->Constraint[Q->NbConstraints-1]+1, Q->Dimension) == -1)
372 Q->NbConstraints--;
374 if (!Constraints) {
375 dim = Q->Dimension;
376 red = gf_base::create(Polyhedron_Copy(context), dim, nparam, options);
377 red->base->init(Q);
378 Constraints = Matrix_Alloc(Q->NbConstraints, Q->Dimension);
379 for (int i = 0; i < Q->NbConstraints; ++i) {
380 Vector_Copy(Q->Constraint[i]+1, Constraints->p[i], Q->Dimension);
382 } else {
383 assert(Q->Dimension == dim);
384 for (int i = 0; i < Q->NbConstraints; ++i) {
385 int j;
386 for (j = 0; j < Constraints->NbRows; ++j)
387 if (Vector_Equal(Q->Constraint[i]+1, Constraints->p[j],
388 Q->Dimension))
389 break;
390 assert(j < Constraints->NbRows);
394 for (int i = 0; i < Q->NbRays; ++i) {
395 if (!value_pos_p(Q->Ray[i][dim+1]))
396 continue;
398 Polyhedron *C = supporting_cone(Q, i);
400 if (First_Non_Zero(C->Constraint[C->NbConstraints-1]+1,
401 C->Dimension) == -1)
402 C->NbConstraints--;
404 int *pos = new int[1+C->NbConstraints];
405 pos[0] = C->NbConstraints;
406 int l = 0;
407 for (int k = 0; k < Constraints->NbRows; ++k) {
408 for (int j = 0; j < C->NbConstraints; ++j) {
409 if (Vector_Equal(C->Constraint[j]+1, Constraints->p[k],
410 C->Dimension)) {
411 pos[1+l++] = k;
412 break;
416 assert(l == C->NbConstraints);
418 int j;
419 for (j = 0; j < cones.size(); ++j)
420 if (!memcmp(pos, cones[j].pos, (1+C->NbConstraints)*sizeof(int)))
421 break;
422 if (j == cones.size())
423 cones.push_back(cone(pos));
424 else
425 delete [] pos;
427 Polyhedron_Free(C);
429 int k;
430 for (k = 0; k < cones[j].vertices.size(); ++k)
431 if (Vector_Equal(Q->Ray[i]+1, cones[j].vertices[k].first->p,
432 Q->Dimension+1))
433 break;
435 if (k == cones[j].vertices.size()) {
436 Vector *vertex = Vector_Alloc(Q->Dimension+1);
437 Vector_Copy(Q->Ray[i]+1, vertex->p, Q->Dimension+1);
438 cones[j].vertices.push_back(pair<Vector*,QQ>(vertex, c));
439 } else {
440 cones[j].vertices[k].second += c;
441 if (cones[j].vertices[k].second.n == 0) {
442 int size = cones[j].vertices.size();
443 Vector_Free(cones[j].vertices[k].first);
444 if (k < size-1)
445 cones[j].vertices[k] = cones[j].vertices[size-1];
446 cones[j].vertices.pop_back();
451 Polyhedron_Free(Q);
452 return true;
454 gen_fun *compute() {
455 if (!red)
456 return NULL;
457 for (int i = 0; i < cones.size(); ++i) {
458 Matrix *M = Matrix_Alloc(cones[i].pos[0], 1+Constraints->NbColumns+1);
459 Polyhedron *Cone;
460 for (int j = 0; j <cones[i].pos[0]; ++j) {
461 value_set_si(M->p[j][0], 1);
462 Vector_Copy(Constraints->p[cones[i].pos[1+j]], M->p[j]+1,
463 Constraints->NbColumns);
465 Cone = Constraints2Polyhedron(M, options->MaxRays);
466 Matrix_Free(M);
467 for (int j = 0; j < cones[i].vertices.size(); ++j) {
468 red->base->do_vertex_cone(cones[i].vertices[j].second,
469 Polyhedron_Copy(Cone),
470 cones[i].vertices[j].first->p, options);
472 Polyhedron_Free(Cone);
474 if (CP)
475 red->gf->substitute(CP);
476 return red->gf;
478 void print(std::ostream& os) const {
479 for (int i = 0; i < cones.size(); ++i) {
480 os << "[";
481 for (int j = 0; j < cones[i].pos[0]; ++j) {
482 if (j)
483 os << ", ";
484 os << cones[i].pos[1+j];
486 os << "]" << endl;
487 for (int j = 0; j < cones[i].vertices.size(); ++j) {
488 Vector_Print(stderr, P_VALUE_FMT, cones[i].vertices[j].first);
489 os << cones[i].vertices[j].second << endl;
493 ~parallel_polytopes() {
494 for (int i = 0; i < cones.size(); ++i) {
495 delete [] cones[i].pos;
496 for (int j = 0; j < cones[i].vertices.size(); ++j)
497 Vector_Free(cones[i].vertices[j].first);
499 if (Constraints)
500 Matrix_Free(Constraints);
501 if (CP)
502 Matrix_Free(CP);
503 if (T)
504 Matrix_Free(T);
505 delete red;
509 gen_fun *gen_fun::Hadamard_product(const gen_fun *gf, barvinok_options *options)
511 QQ one(1, 1);
512 Polyhedron *C = DomainIntersection(context, gf->context, options->MaxRays);
513 Polyhedron *U = Universe_Polyhedron(C->Dimension);
514 gen_fun *sum = new gen_fun(C);
515 for (short_rat_list::iterator i = term.begin(); i != term.end(); ++i) {
516 for (short_rat_list::iterator i2 = gf->term.begin(); i2 != gf->term.end();
517 ++i2) {
518 int d = (*i)->d.power.NumCols();
519 int k1 = (*i)->d.power.NumRows();
520 int k2 = (*i2)->d.power.NumRows();
521 assert((*i)->d.power.NumCols() == (*i2)->d.power.NumCols());
523 parallel_polytopes pp((*i)->n.power.NumRows() *
524 (*i2)->n.power.NumRows(),
525 sum->context, d, options);
527 for (int j = 0; j < (*i)->n.power.NumRows(); ++j) {
528 for (int j2 = 0; j2 < (*i2)->n.power.NumRows(); ++j2) {
529 Matrix *M = Matrix_Alloc(k1+k2+d+d, 1+k1+k2+d+1);
530 for (int k = 0; k < k1+k2; ++k) {
531 value_set_si(M->p[k][0], 1);
532 value_set_si(M->p[k][1+k], 1);
534 for (int k = 0; k < d; ++k) {
535 value_set_si(M->p[k1+k2+k][1+k1+k2+k], -1);
536 zz2value((*i)->n.power[j][k], M->p[k1+k2+k][1+k1+k2+d]);
537 for (int l = 0; l < k1; ++l)
538 zz2value((*i)->d.power[l][k], M->p[k1+k2+k][1+l]);
540 for (int k = 0; k < d; ++k) {
541 value_set_si(M->p[k1+k2+d+k][1+k1+k2+k], -1);
542 zz2value((*i2)->n.power[j2][k],
543 M->p[k1+k2+d+k][1+k1+k2+d]);
544 for (int l = 0; l < k2; ++l)
545 zz2value((*i2)->d.power[l][k],
546 M->p[k1+k2+d+k][1+k1+l]);
548 Polyhedron *P = Constraints2Polyhedron(M, options->MaxRays);
549 Matrix_Free(M);
551 QQ c = (*i)->n.coeff[j];
552 c *= (*i2)->n.coeff[j2];
553 if (!pp.add(c, P)) {
554 gen_fun *t = barvinok_series_with_options(P, U, options);
555 sum->add(c, t);
556 delete t;
559 Polyhedron_Free(P);
563 gen_fun *t = pp.compute();
564 if (t) {
565 sum->add(one, t);
566 delete t;
570 Polyhedron_Free(U);
571 return sum;
574 void gen_fun::add_union(gen_fun *gf, barvinok_options *options)
576 QQ one(1, 1), mone(-1, 1);
578 gen_fun *hp = Hadamard_product(gf, options);
579 add(one, gf);
580 add(mone, hp);
581 delete hp;
584 static void Polyhedron_Shift(Polyhedron *P, Vector *offset)
586 Value tmp;
587 value_init(tmp);
588 for (int i = 0; i < P->NbConstraints; ++i) {
589 Inner_Product(P->Constraint[i]+1, offset->p, P->Dimension, &tmp);
590 value_subtract(P->Constraint[i][1+P->Dimension],
591 P->Constraint[i][1+P->Dimension], tmp);
593 for (int i = 0; i < P->NbRays; ++i) {
594 if (value_notone_p(P->Ray[i][0]))
595 continue;
596 if (value_zero_p(P->Ray[i][1+P->Dimension]))
597 continue;
598 Vector_Combine(P->Ray[i]+1, offset->p, P->Ray[i]+1,
599 P->Ray[i][0], P->Ray[i][1+P->Dimension], P->Dimension);
601 value_clear(tmp);
604 void gen_fun::shift(const vec_ZZ& offset)
606 for (short_rat_list::iterator i = term.begin(); i != term.end(); ++i)
607 for (int j = 0; j < (*i)->n.power.NumRows(); ++j)
608 (*i)->n.power[j] += offset;
610 Vector *v = Vector_Alloc(offset.length());
611 zz2values(offset, v->p);
612 Polyhedron_Shift(context, v);
613 Vector_Free(v);
616 /* Divide the generating functin by 1/(1-z^power).
617 * The effect on the corresponding explicit function f(x) is
618 * f'(x) = \sum_{i=0}^\infty f(x - i * power)
620 void gen_fun::divide(const vec_ZZ& power)
622 for (short_rat_list::iterator i = term.begin(); i != term.end(); ++i) {
623 int r = (*i)->d.power.NumRows();
624 int c = (*i)->d.power.NumCols();
625 (*i)->d.power.SetDims(r+1, c);
626 (*i)->d.power[r] = power;
629 Vector *v = Vector_Alloc(1+power.length()+1);
630 value_set_si(v->p[0], 1);
631 zz2values(power, v->p+1);
632 Polyhedron *C = AddRays(v->p, 1, context, context->NbConstraints+1);
633 Vector_Free(v);
634 Polyhedron_Free(context);
635 context = C;
638 static void print_power(std::ostream& os, QQ& c, vec_ZZ& p,
639 unsigned int nparam, char **param_name)
641 bool first = true;
643 for (int i = 0; i < p.length(); ++i) {
644 if (p[i] == 0)
645 continue;
646 if (first) {
647 if (c.n == -1 && c.d == 1)
648 os << "-";
649 else if (c.n != 1 || c.d != 1) {
650 os << c.n;
651 if (c.d != 1)
652 os << " / " << c.d;
653 os << "*";
655 first = false;
656 } else
657 os << "*";
658 if (i < nparam)
659 os << param_name[i];
660 else
661 os << "x" << i;
662 if (p[i] == 1)
663 continue;
664 if (p[i] < 0)
665 os << "^(" << p[i] << ")";
666 else
667 os << "^" << p[i];
669 if (first) {
670 os << c.n;
671 if (c.d != 1)
672 os << " / " << c.d;
676 void gen_fun::print(std::ostream& os, unsigned int nparam, char **param_name) const
678 QQ mone(-1, 1);
679 for (short_rat_list::iterator i = term.begin(); i != term.end(); ++i) {
680 if (i != term.begin())
681 os << " + ";
682 os << "(";
683 for (int j = 0; j < (*i)->n.coeff.length(); ++j) {
684 if (j != 0 && (*i)->n.coeff[j].n > 0)
685 os << "+";
686 print_power(os, (*i)->n.coeff[j], (*i)->n.power[j],
687 nparam, param_name);
689 os << ")/(";
690 for (int j = 0; j < (*i)->d.power.NumRows(); ++j) {
691 if (j != 0)
692 os << " * ";
693 os << "(1";
694 print_power(os, mone, (*i)->d.power[j], nparam, param_name);
695 os << ")";
697 os << ")";
701 gen_fun::operator evalue *() const
703 evalue *EP = NULL;
704 evalue factor;
705 value_init(factor.d);
706 value_init(factor.x.n);
707 for (short_rat_list::iterator i = term.begin(); i != term.end(); ++i) {
708 unsigned nvar = (*i)->d.power.NumRows();
709 unsigned nparam = (*i)->d.power.NumCols();
710 Matrix *C = Matrix_Alloc(nparam + nvar, 1 + nvar + nparam + 1);
711 mat_ZZ& d = (*i)->d.power;
712 Polyhedron *U = context ? context : Universe_Polyhedron(nparam);
714 for (int j = 0; j < (*i)->n.coeff.length(); ++j) {
715 for (int r = 0; r < nparam; ++r) {
716 value_set_si(C->p[r][0], 0);
717 for (int c = 0; c < nvar; ++c) {
718 zz2value(d[c][r], C->p[r][1+c]);
720 Vector_Set(&C->p[r][1+nvar], 0, nparam);
721 value_set_si(C->p[r][1+nvar+r], -1);
722 zz2value((*i)->n.power[j][r], C->p[r][1+nvar+nparam]);
724 for (int r = 0; r < nvar; ++r) {
725 value_set_si(C->p[nparam+r][0], 1);
726 Vector_Set(&C->p[nparam+r][1], 0, nvar + nparam + 1);
727 value_set_si(C->p[nparam+r][1+r], 1);
729 Polyhedron *P = Constraints2Polyhedron(C, 0);
730 evalue *E = barvinok_enumerate_ev(P, U, 0);
731 Polyhedron_Free(P);
732 if (EVALUE_IS_ZERO(*E)) {
733 free_evalue_refs(E);
734 free(E);
735 continue;
737 zz2value((*i)->n.coeff[j].n, factor.x.n);
738 zz2value((*i)->n.coeff[j].d, factor.d);
739 emul(&factor, E);
741 Matrix_Print(stdout, P_VALUE_FMT, C);
742 char *test[] = { "A", "B", "C", "D", "E", "F", "G" };
743 print_evalue(stdout, E, test);
745 if (!EP)
746 EP = E;
747 else {
748 eadd(E, EP);
749 free_evalue_refs(E);
750 free(E);
753 Matrix_Free(C);
754 if (!context)
755 Polyhedron_Free(U);
757 value_clear(factor.d);
758 value_clear(factor.x.n);
759 return EP;
762 ZZ gen_fun::coefficient(Value* params, barvinok_options *options) const
764 if (context && !in_domain(context, params))
765 return ZZ::zero();
767 QQ sum(0, 1);
769 for (short_rat_list::iterator i = term.begin(); i != term.end(); ++i)
770 sum += (*i)->coefficient(params, options);
772 assert(sum.d == 1);
773 return sum.n;
776 void gen_fun::coefficient(Value* params, Value* c) const
778 barvinok_options *options = barvinok_options_new_with_defaults();
780 ZZ coeff = coefficient(params, options);
782 zz2value(coeff, *c);
784 free(options);
787 gen_fun *gen_fun::summate(int nvar, barvinok_options *options) const
789 int dim = context->Dimension;
790 int nparam = dim - nvar;
791 reducer *red;
792 gen_fun *gf;
794 if (options->incremental_specialization == 1) {
795 red = new partial_ireducer(Polyhedron_Project(context, nparam), dim, nparam);
796 } else
797 red = new partial_reducer(Polyhedron_Project(context, nparam), dim, nparam);
798 for (;;) {
799 try {
800 red->init(context);
801 for (short_rat_list::iterator i = term.begin(); i != term.end(); ++i)
802 for (int j = 0; j < (*i)->n.power.NumRows(); ++j)
803 red->reduce((*i)->n.coeff[j], (*i)->n.power[j], (*i)->d.power);
804 break;
805 } catch (OrthogonalException &e) {
806 red->reset();
809 gf = red->get_gf();
810 delete red;
811 return gf;
814 /* returns true if the set was finite and false otherwise */
815 bool gen_fun::summate(Value *sum) const
817 if (term.size() == 0) {
818 value_set_si(*sum, 0);
819 return true;
822 int maxlen = 0;
823 for (short_rat_list::iterator i = term.begin(); i != term.end(); ++i)
824 if ((*i)->d.power.NumRows() > maxlen)
825 maxlen = (*i)->d.power.NumRows();
827 infinite_icounter cnt((*term.begin())->d.power.NumCols(), maxlen);
828 for (short_rat_list::iterator i = term.begin(); i != term.end(); ++i)
829 for (int j = 0; j < (*i)->n.power.NumRows(); ++j)
830 cnt.reduce((*i)->n.coeff[j], (*i)->n.power[j], (*i)->d.power);
832 for (int i = 1; i <= maxlen; ++i)
833 if (value_notzero_p(mpq_numref(cnt.count[i]))) {
834 value_set_si(*sum, -1);
835 return false;
838 assert(value_one_p(mpq_denref(cnt.count[0])));
839 value_assign(*sum, mpq_numref(cnt.count[0]));
840 return true;