5 #include <barvinok/genfun.h>
6 #include <barvinok/barvinok.h>
7 #include "conversion.h"
8 #include "genfun_constructor.h"
17 static void lex_order_terms(struct short_rat
* rat
)
19 for (int i
= 0; i
< rat
->n
.power
.NumRows(); ++i
) {
21 for (int j
= i
+1; j
< rat
->n
.power
.NumRows(); ++j
)
22 if (lex_cmp(rat
->n
.power
[j
], rat
->n
.power
[m
]) < 0)
25 vec_ZZ tmp
= rat
->n
.power
[m
];
26 rat
->n
.power
[m
] = rat
->n
.power
[i
];
27 rat
->n
.power
[i
] = tmp
;
28 QQ tmp_coeff
= rat
->n
.coeff
[m
];
29 rat
->n
.coeff
[m
] = rat
->n
.coeff
[i
];
30 rat
->n
.coeff
[i
] = tmp_coeff
;
35 short_rat::short_rat(Value c
)
38 value2zz(c
, n
.coeff
[0].n
);
40 n
.power
.SetDims(1, 0);
41 d
.power
.SetDims(0, 0);
44 short_rat::short_rat(const QQ
& c
, const vec_ZZ
& num
, const mat_ZZ
& den
)
50 n
.power
.SetDims(1, num
.length());
56 void short_rat::normalize()
58 /* Make all powers in denominator lexico-positive */
59 for (int i
= 0; i
< d
.power
.NumRows(); ++i
) {
61 for (j
= 0; j
< d
.power
.NumCols(); ++j
)
62 if (d
.power
[i
][j
] != 0)
64 assert(j
< d
.power
.NumCols());
65 if (d
.power
[i
][j
] < 0) {
66 d
.power
[i
] = -d
.power
[i
];
67 for (int k
= 0; k
< n
.coeff
.length(); ++k
) {
68 n
.coeff
[k
].n
= -n
.coeff
[k
].n
;
69 n
.power
[k
] += d
.power
[i
];
74 /* Order powers in denominator */
75 lex_order_rows(d
.power
);
78 void short_rat::add(short_rat
*r
)
80 for (int i
= 0; i
< r
->n
.power
.NumRows(); ++i
) {
81 int len
= n
.coeff
.length();
83 for (j
= 0; j
< len
; ++j
)
84 if (r
->n
.power
[i
] == n
.power
[j
])
87 n
.coeff
[j
] += r
->n
.coeff
[i
];
88 if (n
.coeff
[j
].n
== 0) {
90 n
.power
[j
] = n
.power
[len
-1];
91 n
.coeff
[j
] = n
.coeff
[len
-1];
93 int dim
= n
.power
.NumCols();
94 n
.coeff
.SetLength(len
-1);
95 n
.power
.SetDims(len
-1, dim
);
98 int dim
= n
.power
.NumCols();
99 n
.coeff
.SetLength(len
+1);
100 n
.power
.SetDims(len
+1, dim
);
101 n
.coeff
[len
] = r
->n
.coeff
[i
];
102 n
.power
[len
] = r
->n
.power
[i
];
107 bool short_rat::reduced()
109 int dim
= n
.power
.NumCols();
110 lex_order_terms(this);
111 if (n
.power
.NumRows() % 2 == 0) {
112 if (n
.coeff
[0].n
== -n
.coeff
[1].n
&&
113 n
.coeff
[0].d
== n
.coeff
[1].d
) {
114 vec_ZZ step
= n
.power
[1] - n
.power
[0];
116 for (k
= 1; k
< n
.power
.NumRows()/2; ++k
) {
117 if (n
.coeff
[2*k
].n
!= -n
.coeff
[2*k
+1].n
||
118 n
.coeff
[2*k
].d
!= n
.coeff
[2*k
+1].d
)
120 if (step
!= n
.power
[2*k
+1] - n
.power
[2*k
])
123 if (k
== n
.power
.NumRows()/2) {
124 for (k
= 0; k
< d
.power
.NumRows(); ++k
)
125 if (d
.power
[k
] == step
)
127 if (k
< d
.power
.NumRows()) {
128 for (++k
; k
< d
.power
.NumRows(); ++k
)
129 d
.power
[k
-1] = d
.power
[k
];
130 d
.power
.SetDims(k
-1, dim
);
131 for (k
= 1; k
< n
.power
.NumRows()/2; ++k
) {
132 n
.coeff
[k
] = n
.coeff
[2*k
];
133 n
.power
[k
] = n
.power
[2*k
];
135 n
.coeff
.SetLength(k
);
136 n
.power
.SetDims(k
, dim
);
145 gen_fun::gen_fun(Value c
)
147 short_rat
*r
= new short_rat(c
);
148 context
= Universe_Polyhedron(0);
152 void gen_fun::add(const QQ
& c
, const vec_ZZ
& num
, const mat_ZZ
& den
)
157 short_rat
* r
= new short_rat(c
, num
, den
);
159 for (int i
= 0; i
< term
.size(); ++i
)
160 if (lex_cmp(term
[i
]->d
.power
, r
->d
.power
) == 0) {
162 if (term
[i
]->n
.coeff
.length() == 0) {
164 if (i
!= term
.size()-1)
165 term
[i
] = term
[term
.size()-1];
167 } else if (term
[i
]->reduced()) {
169 /* we've modified term[i], so removed it
170 * and add it back again
173 if (i
!= term
.size()-1)
174 term
[i
] = term
[term
.size()-1];
186 void gen_fun::add(const QQ
& c
, const gen_fun
*gf
)
189 for (int i
= 0; i
< gf
->term
.size(); ++i
) {
190 for (int j
= 0; j
< gf
->term
[i
]->n
.power
.NumRows(); ++j
) {
192 p
*= gf
->term
[i
]->n
.coeff
[j
];
193 add(p
, gf
->term
[i
]->n
.power
[j
], gf
->term
[i
]->d
.power
);
198 static void split_param_compression(Matrix
*CP
, mat_ZZ
& map
, vec_ZZ
& offset
)
200 Matrix
*T
= Transpose(CP
);
201 matrix2zz(T
, map
, T
->NbRows
-1, T
->NbColumns
-1);
202 values2zz(T
->p
[T
->NbRows
-1], offset
, T
->NbColumns
-1);
207 * Perform the substitution specified by CP
209 * CP is a homogeneous matrix that maps a set of "compressed parameters"
210 * to the original set of parameters.
212 * This function is applied to a gen_fun computed with the compressed parameters
213 * and adapts it to refer to the original parameters.
215 * That is, if y are the compressed parameters and x = A y + b are the original
216 * parameters, then we want the coefficient of the monomial t^y in the original
217 * generating function to be the coefficient of the monomial u^x in the resulting
218 * generating function.
219 * The original generating function has the form
221 * a t^m/(1-t^n) = a t^m + a t^{m+n} + a t^{m+2n} + ...
223 * Since each term t^y should correspond to a term u^x, with x = A y + b, we want
225 * a u^{A m + b} + a u^{A (m+n) + b} + a u^{A (m+2n) +b} + ... =
227 * = a u^{A m + b}/(1-u^{A n})
229 * Therefore, we multiply the powers m and n in both numerator and denominator by A
230 * and add b to the power in the numerator.
231 * Since the above powers are stored as row vectors m^T and n^T,
232 * we compute, say, m'^T = m^T A^T to obtain m' = A m.
234 * The pair (map, offset) contains the same information as CP.
235 * map is the transpose of the linear part of CP, while offset is the constant part.
237 void gen_fun::substitute(Matrix
*CP
)
241 split_param_compression(CP
, map
, offset
);
242 Polyhedron
*C
= Polyhedron_Image(context
, CP
, 0);
243 Polyhedron_Free(context
);
245 for (int i
= 0; i
< term
.size(); ++i
) {
246 term
[i
]->d
.power
*= map
;
247 term
[i
]->n
.power
*= map
;
248 for (int j
= 0; j
< term
[i
]->n
.power
.NumRows(); ++j
)
249 term
[i
]->n
.power
[j
] += offset
;
255 vector
<pair
<Vector
*, QQ
> > vertices
;
256 cone(int *pos
) : pos(pos
) {}
259 #ifndef HAVE_COMPRESS_PARMS
260 static Matrix
*compress_parms(Matrix
*M
, unsigned nparam
)
266 struct parallel_polytopes
{
274 barvinok_options
*options
;
276 parallel_polytopes(int n
, Polyhedron
*context
, int nparam
,
277 barvinok_options
*options
) :
278 context(context
), dim(-1), nparam(nparam
),
285 bool add(const QQ
& c
, Polyhedron
*P
) {
288 for (i
= 0; i
< P
->NbEq
; ++i
)
289 if (First_Non_Zero(P
->Constraint
[i
]+1,
290 P
->Dimension
-nparam
) == -1)
295 Polyhedron
*Q
= remove_equalities_p(Polyhedron_Copy(P
), P
->Dimension
-nparam
,
297 POL_ENSURE_VERTICES(Q
);
307 M
= Matrix_Alloc(Q
->NbEq
, Q
->Dimension
+2);
308 Vector_Copy(Q
->Constraint
[0], M
->p
[0], Q
->NbEq
* (Q
->Dimension
+2));
309 CP
= compress_parms(M
, nparam
);
310 T
= align_matrix(CP
, Q
->Dimension
+1);
313 R
= Polyhedron_Preimage(Q
, T
, options
->MaxRays
);
315 Q
= remove_equalities_p(R
, R
->Dimension
-nparam
, NULL
);
317 assert(Q
->NbEq
== 0);
319 if (First_Non_Zero(Q
->Constraint
[Q
->NbConstraints
-1]+1, Q
->Dimension
) == -1)
324 red
= gf_base::create(Polyhedron_Copy(context
), dim
, nparam
, options
);
326 Constraints
= Matrix_Alloc(Q
->NbConstraints
, Q
->Dimension
);
327 for (int i
= 0; i
< Q
->NbConstraints
; ++i
) {
328 Vector_Copy(Q
->Constraint
[i
]+1, Constraints
->p
[i
], Q
->Dimension
);
331 assert(Q
->Dimension
== dim
);
332 for (int i
= 0; i
< Q
->NbConstraints
; ++i
) {
334 for (j
= 0; j
< Constraints
->NbRows
; ++j
)
335 if (Vector_Equal(Q
->Constraint
[i
]+1, Constraints
->p
[j
],
338 assert(j
< Constraints
->NbRows
);
342 for (int i
= 0; i
< Q
->NbRays
; ++i
) {
343 if (!value_pos_p(Q
->Ray
[i
][dim
+1]))
346 Polyhedron
*C
= supporting_cone(Q
, i
);
348 if (First_Non_Zero(C
->Constraint
[C
->NbConstraints
-1]+1,
352 int *pos
= new int[1+C
->NbConstraints
];
353 pos
[0] = C
->NbConstraints
;
355 for (int k
= 0; k
< Constraints
->NbRows
; ++k
) {
356 for (int j
= 0; j
< C
->NbConstraints
; ++j
) {
357 if (Vector_Equal(C
->Constraint
[j
]+1, Constraints
->p
[k
],
364 assert(l
== C
->NbConstraints
);
367 for (j
= 0; j
< cones
.size(); ++j
)
368 if (!memcmp(pos
, cones
[j
].pos
, (1+C
->NbConstraints
)*sizeof(int)))
370 if (j
== cones
.size())
371 cones
.push_back(cone(pos
));
378 for (k
= 0; k
< cones
[j
].vertices
.size(); ++k
)
379 if (Vector_Equal(Q
->Ray
[i
]+1, cones
[j
].vertices
[k
].first
->p
,
383 if (k
== cones
[j
].vertices
.size()) {
384 Vector
*vertex
= Vector_Alloc(Q
->Dimension
+1);
385 Vector_Copy(Q
->Ray
[i
]+1, vertex
->p
, Q
->Dimension
+1);
386 cones
[j
].vertices
.push_back(pair
<Vector
*,QQ
>(vertex
, c
));
388 cones
[j
].vertices
[k
].second
+= c
;
389 if (cones
[j
].vertices
[k
].second
.n
== 0) {
390 int size
= cones
[j
].vertices
.size();
391 Vector_Free(cones
[j
].vertices
[k
].first
);
393 cones
[j
].vertices
[k
] = cones
[j
].vertices
[size
-1];
394 cones
[j
].vertices
.pop_back();
405 for (int i
= 0; i
< cones
.size(); ++i
) {
406 Matrix
*M
= Matrix_Alloc(cones
[i
].pos
[0], 1+Constraints
->NbColumns
+1);
408 for (int j
= 0; j
<cones
[i
].pos
[0]; ++j
) {
409 value_set_si(M
->p
[j
][0], 1);
410 Vector_Copy(Constraints
->p
[cones
[i
].pos
[1+j
]], M
->p
[j
]+1,
411 Constraints
->NbColumns
);
413 Cone
= Constraints2Polyhedron(M
, options
->MaxRays
);
415 for (int j
= 0; j
< cones
[i
].vertices
.size(); ++j
) {
416 red
->base
->do_vertex_cone(cones
[i
].vertices
[j
].second
,
417 Polyhedron_Copy(Cone
),
418 cones
[i
].vertices
[j
].first
->p
, options
);
420 Polyhedron_Free(Cone
);
423 red
->gf
->substitute(CP
);
426 void print(std::ostream
& os
) const {
427 for (int i
= 0; i
< cones
.size(); ++i
) {
429 for (int j
= 0; j
< cones
[i
].pos
[0]; ++j
) {
432 os
<< cones
[i
].pos
[1+j
];
435 for (int j
= 0; j
< cones
[i
].vertices
.size(); ++j
) {
436 Vector_Print(stderr
, P_VALUE_FMT
, cones
[i
].vertices
[j
].first
);
437 os
<< cones
[i
].vertices
[j
].second
<< endl
;
441 ~parallel_polytopes() {
442 for (int i
= 0; i
< cones
.size(); ++i
) {
443 delete [] cones
[i
].pos
;
444 for (int j
= 0; j
< cones
[i
].vertices
.size(); ++j
)
445 Vector_Free(cones
[i
].vertices
[j
].first
);
448 Matrix_Free(Constraints
);
457 gen_fun
*gen_fun::Hadamard_product(const gen_fun
*gf
, barvinok_options
*options
)
460 Polyhedron
*C
= DomainIntersection(context
, gf
->context
, options
->MaxRays
);
461 Polyhedron
*U
= Universe_Polyhedron(C
->Dimension
);
462 gen_fun
*sum
= new gen_fun(C
);
463 for (int i
= 0; i
< term
.size(); ++i
) {
464 for (int i2
= 0; i2
< gf
->term
.size(); ++i2
) {
465 int d
= term
[i
]->d
.power
.NumCols();
466 int k1
= term
[i
]->d
.power
.NumRows();
467 int k2
= gf
->term
[i2
]->d
.power
.NumRows();
468 assert(term
[i
]->d
.power
.NumCols() == gf
->term
[i2
]->d
.power
.NumCols());
470 parallel_polytopes
pp(term
[i
]->n
.power
.NumRows() *
471 gf
->term
[i2
]->n
.power
.NumRows(),
472 sum
->context
, d
, options
);
474 for (int j
= 0; j
< term
[i
]->n
.power
.NumRows(); ++j
) {
475 for (int j2
= 0; j2
< gf
->term
[i2
]->n
.power
.NumRows(); ++j2
) {
476 Matrix
*M
= Matrix_Alloc(k1
+k2
+d
+d
, 1+k1
+k2
+d
+1);
477 for (int k
= 0; k
< k1
+k2
; ++k
) {
478 value_set_si(M
->p
[k
][0], 1);
479 value_set_si(M
->p
[k
][1+k
], 1);
481 for (int k
= 0; k
< d
; ++k
) {
482 value_set_si(M
->p
[k1
+k2
+k
][1+k1
+k2
+k
], -1);
483 zz2value(term
[i
]->n
.power
[j
][k
], M
->p
[k1
+k2
+k
][1+k1
+k2
+d
]);
484 for (int l
= 0; l
< k1
; ++l
)
485 zz2value(term
[i
]->d
.power
[l
][k
], M
->p
[k1
+k2
+k
][1+l
]);
487 for (int k
= 0; k
< d
; ++k
) {
488 value_set_si(M
->p
[k1
+k2
+d
+k
][1+k1
+k2
+k
], -1);
489 zz2value(gf
->term
[i2
]->n
.power
[j2
][k
],
490 M
->p
[k1
+k2
+d
+k
][1+k1
+k2
+d
]);
491 for (int l
= 0; l
< k2
; ++l
)
492 zz2value(gf
->term
[i2
]->d
.power
[l
][k
],
493 M
->p
[k1
+k2
+d
+k
][1+k1
+l
]);
495 Polyhedron
*P
= Constraints2Polyhedron(M
, options
->MaxRays
);
498 QQ c
= term
[i
]->n
.coeff
[j
];
499 c
*= gf
->term
[i2
]->n
.coeff
[j2
];
501 gen_fun
*t
= barvinok_series(P
, U
, options
->MaxRays
);
510 gen_fun
*t
= pp
.compute();
521 void gen_fun::add_union(gen_fun
*gf
, barvinok_options
*options
)
523 QQ
one(1, 1), mone(-1, 1);
525 gen_fun
*hp
= Hadamard_product(gf
, options
);
531 static void Polyhedron_Shift(Polyhedron
*P
, Vector
*offset
)
535 for (int i
= 0; i
< P
->NbConstraints
; ++i
) {
536 Inner_Product(P
->Constraint
[i
]+1, offset
->p
, P
->Dimension
, &tmp
);
537 value_subtract(P
->Constraint
[i
][1+P
->Dimension
],
538 P
->Constraint
[i
][1+P
->Dimension
], tmp
);
540 for (int i
= 0; i
< P
->NbRays
; ++i
) {
541 if (value_notone_p(P
->Ray
[i
][0]))
543 if (value_zero_p(P
->Ray
[i
][1+P
->Dimension
]))
545 Vector_Combine(P
->Ray
[i
]+1, offset
->p
, P
->Ray
[i
]+1,
546 P
->Ray
[i
][0], P
->Ray
[i
][1+P
->Dimension
], P
->Dimension
);
551 void gen_fun::shift(const vec_ZZ
& offset
)
553 for (int i
= 0; i
< term
.size(); ++i
)
554 for (int j
= 0; j
< term
[i
]->n
.power
.NumRows(); ++j
)
555 term
[i
]->n
.power
[j
] += offset
;
557 Vector
*v
= Vector_Alloc(offset
.length());
558 zz2values(offset
, v
->p
);
559 Polyhedron_Shift(context
, v
);
563 /* Divide the generating functin by 1/(1-z^power).
564 * The effect on the corresponding explicit function f(x) is
565 * f'(x) = \sum_{i=0}^\infty f(x - i * power)
567 void gen_fun::divide(const vec_ZZ
& power
)
569 for (int i
= 0; i
< term
.size(); ++i
) {
570 int r
= term
[i
]->d
.power
.NumRows();
571 int c
= term
[i
]->d
.power
.NumCols();
572 term
[i
]->d
.power
.SetDims(r
+1, c
);
573 term
[i
]->d
.power
[r
] = power
;
576 Vector
*v
= Vector_Alloc(1+power
.length()+1);
577 value_set_si(v
->p
[0], 1);
578 zz2values(power
, v
->p
+1);
579 Polyhedron
*C
= AddRays(v
->p
, 1, context
, context
->NbConstraints
+1);
581 Polyhedron_Free(context
);
585 static void print_power(std::ostream
& os
, QQ
& c
, vec_ZZ
& p
,
586 unsigned int nparam
, char **param_name
)
590 for (int i
= 0; i
< p
.length(); ++i
) {
594 if (c
.n
== -1 && c
.d
== 1)
596 else if (c
.n
!= 1 || c
.d
!= 1) {
612 os
<< "^(" << p
[i
] << ")";
623 void gen_fun::print(std::ostream
& os
, unsigned int nparam
, char **param_name
) const
626 for (int i
= 0; i
< term
.size(); ++i
) {
630 for (int j
= 0; j
< term
[i
]->n
.coeff
.length(); ++j
) {
631 if (j
!= 0 && term
[i
]->n
.coeff
[j
].n
> 0)
633 print_power(os
, term
[i
]->n
.coeff
[j
], term
[i
]->n
.power
[j
],
637 for (int j
= 0; j
< term
[i
]->d
.power
.NumRows(); ++j
) {
641 print_power(os
, mone
, term
[i
]->d
.power
[j
], nparam
, param_name
);
648 gen_fun::operator evalue
*() const
652 value_init(factor
.d
);
653 value_init(factor
.x
.n
);
654 for (int i
= 0; i
< term
.size(); ++i
) {
655 unsigned nvar
= term
[i
]->d
.power
.NumRows();
656 unsigned nparam
= term
[i
]->d
.power
.NumCols();
657 Matrix
*C
= Matrix_Alloc(nparam
+ nvar
, 1 + nvar
+ nparam
+ 1);
658 mat_ZZ
& d
= term
[i
]->d
.power
;
659 Polyhedron
*U
= context
? context
: Universe_Polyhedron(nparam
);
661 for (int j
= 0; j
< term
[i
]->n
.coeff
.length(); ++j
) {
662 for (int r
= 0; r
< nparam
; ++r
) {
663 value_set_si(C
->p
[r
][0], 0);
664 for (int c
= 0; c
< nvar
; ++c
) {
665 zz2value(d
[c
][r
], C
->p
[r
][1+c
]);
667 Vector_Set(&C
->p
[r
][1+nvar
], 0, nparam
);
668 value_set_si(C
->p
[r
][1+nvar
+r
], -1);
669 zz2value(term
[i
]->n
.power
[j
][r
], C
->p
[r
][1+nvar
+nparam
]);
671 for (int r
= 0; r
< nvar
; ++r
) {
672 value_set_si(C
->p
[nparam
+r
][0], 1);
673 Vector_Set(&C
->p
[nparam
+r
][1], 0, nvar
+ nparam
+ 1);
674 value_set_si(C
->p
[nparam
+r
][1+r
], 1);
676 Polyhedron
*P
= Constraints2Polyhedron(C
, 0);
677 evalue
*E
= barvinok_enumerate_ev(P
, U
, 0);
679 if (EVALUE_IS_ZERO(*E
)) {
684 zz2value(term
[i
]->n
.coeff
[j
].n
, factor
.x
.n
);
685 zz2value(term
[i
]->n
.coeff
[j
].d
, factor
.d
);
688 Matrix_Print(stdout, P_VALUE_FMT, C);
689 char *test[] = { "A", "B", "C", "D", "E", "F", "G" };
690 print_evalue(stdout, E, test);
704 value_clear(factor
.d
);
705 value_clear(factor
.x
.n
);
709 void gen_fun::coefficient(Value
* params
, Value
* c
) const
711 if (context
&& !in_domain(context
, params
)) {
718 value_init(part
.x
.n
);
721 evalue_set_si(&sum
, 0, 1);
725 for (int i
= 0; i
< term
.size(); ++i
) {
726 unsigned nvar
= term
[i
]->d
.power
.NumRows();
727 unsigned nparam
= term
[i
]->d
.power
.NumCols();
728 Matrix
*C
= Matrix_Alloc(nparam
+ nvar
, 1 + nvar
+ 1);
729 mat_ZZ
& d
= term
[i
]->d
.power
;
731 for (int j
= 0; j
< term
[i
]->n
.coeff
.length(); ++j
) {
732 C
->NbRows
= nparam
+nvar
;
733 for (int r
= 0; r
< nparam
; ++r
) {
734 value_set_si(C
->p
[r
][0], 0);
735 for (int c
= 0; c
< nvar
; ++c
) {
736 zz2value(d
[c
][r
], C
->p
[r
][1+c
]);
738 zz2value(term
[i
]->n
.power
[j
][r
], C
->p
[r
][1+nvar
]);
739 value_subtract(C
->p
[r
][1+nvar
], C
->p
[r
][1+nvar
], params
[r
]);
741 for (int r
= 0; r
< nvar
; ++r
) {
742 value_set_si(C
->p
[nparam
+r
][0], 1);
743 Vector_Set(&C
->p
[nparam
+r
][1], 0, nvar
+ 1);
744 value_set_si(C
->p
[nparam
+r
][1+r
], 1);
746 Polyhedron
*P
= Constraints2Polyhedron(C
, 0);
751 barvinok_count(P
, &tmp
, 0);
753 if (value_zero_p(tmp
))
755 zz2value(term
[i
]->n
.coeff
[j
].n
, part
.x
.n
);
756 zz2value(term
[i
]->n
.coeff
[j
].d
, part
.d
);
757 value_multiply(part
.x
.n
, part
.x
.n
, tmp
);
763 assert(value_one_p(sum
.d
));
764 value_assign(*c
, sum
.x
.n
);
768 value_clear(part
.x
.n
);
770 value_clear(sum
.x
.n
);
773 gen_fun
*gen_fun::summate(int nvar
, barvinok_options
*options
) const
775 int dim
= context
->Dimension
;
776 int nparam
= dim
- nvar
;
780 if (options
->incremental_specialization
== 1) {
781 red
= new partial_ireducer(Polyhedron_Project(context
, nparam
), dim
, nparam
);
783 red
= new partial_reducer(Polyhedron_Project(context
, nparam
), dim
, nparam
);
785 for (int i
= 0; i
< term
.size(); ++i
)
786 for (int j
= 0; j
< term
[i
]->n
.power
.NumRows(); ++j
)
787 red
->reduce(term
[i
]->n
.coeff
[j
], term
[i
]->n
.power
[j
], term
[i
]->d
.power
);
793 /* returns true if the set was finite and false otherwise */
794 bool gen_fun::summate(Value
*sum
) const
796 if (term
.size() == 0) {
797 value_set_si(*sum
, 0);
802 for (int i
= 0; i
< term
.size(); ++i
)
803 if (term
[i
]->d
.power
.NumRows() > maxlen
)
804 maxlen
= term
[i
]->d
.power
.NumRows();
806 infinite_icounter
cnt(term
[0]->d
.power
.NumCols(), maxlen
);
807 for (int i
= 0; i
< term
.size(); ++i
)
808 for (int j
= 0; j
< term
[i
]->n
.power
.NumRows(); ++j
)
809 cnt
.reduce(term
[i
]->n
.coeff
[j
], term
[i
]->n
.power
[j
], term
[i
]->d
.power
);
811 for (int i
= 1; i
<= maxlen
; ++i
)
812 if (value_notzero_p(mpq_numref(cnt
.count
[i
]))) {
813 value_set_si(*sum
, -1);
817 assert(value_one_p(mpq_denref(cnt
.count
[0])));
818 value_assign(*sum
, mpq_numref(cnt
.count
[0]));