4 #include <barvinok/options.h>
7 #include "conversion.h"
8 #include "decomposer.h"
9 #include "lattice_point.h"
11 #include "param_util.h"
13 #include "reduce_domain.h"
21 #ifdef HAVE_GNUCXX_HASHMAP
23 #include <ext/hash_map>
25 #define HASH_MAP __gnu_cxx::hash_map
29 template<> struct hash
< const std::vector
<int> >
31 size_t operator()( const std::vector
<int>& x
) const
33 unsigned long __h
= 0;
34 for (int i
= 0; i
< x
.size(); ++i
)
43 #warning "no hash_map available"
45 #define HASH_MAP std::map
49 #define ALLOC(type) (type*)malloc(sizeof(type))
50 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
52 static ostream
& operator<< (ostream
& os
, const vector
<int> & v
)
55 for (int i
= 0; i
< v
.size(); ++i
) {
64 /* Compares the position of the first non-zero element
65 * in both vectors and the second non-zero element
66 * if the position of the first non-zero element is the same.
68 static int pos_cmp(const void *a
, const void *b
)
71 const Vector
*va
= *(const Vector
**)a
;
72 const Vector
*vb
= *(const Vector
**)b
;
74 pa
= First_Non_Zero(va
->p
, va
->Size
);
75 pb
= First_Non_Zero(vb
->p
, vb
->Size
);
78 pa
= First_Non_Zero(va
->p
+pa
+1, va
->Size
-pa
-1);
79 pb
= First_Non_Zero(vb
->p
+pa
+1, vb
->Size
-pa
-1);
85 /* Represents the vertex and the rays of a vertex cone */
88 /* The coefficients of the rays, ordered according
89 * to the first non-zero coefficient.
94 /* The powers of the coefficients of the rays */
95 struct power
***coeff_power
;
97 /* The coordinates of the integer point in the fundamental
98 * parallelepiped, in the basis formed by the rays of
103 /* Bernoulli polynomials corresponding to each E_vertex */
104 evalue
***bernoulli_t
;
106 vertex_cone(unsigned dim
);
107 void init(const mat_ZZ
&rays
, Param_Vertices
*V
, unsigned max_power
);
110 const evalue
*get_bernoulli(int n
, int i
);
113 for (int i
= 0; i
< dim
; ++i
)
114 Vector_Free(coeff
[i
]);
118 for (int i
= 0; i
< dim
; ++i
)
119 delete [] coeff_power
[i
];
120 delete [] coeff_power
;
121 delete [] bernoulli_t
;
125 vertex_cone::vertex_cone(unsigned dim
) : dim(dim
)
127 E_vertex
= new evalue
*[dim
];
128 bernoulli_t
= new evalue
**[dim
];
130 coeff
= ALLOCN(Vector
*, dim
);
131 for (int i
= 0; i
< dim
; ++i
)
132 coeff
[i
] = Vector_Alloc(dim
);
134 Rays
.NbRows
= Rays
.NbColumns
= dim
;
135 Rays
.p
= ALLOCN(Value
*, dim
);
137 coeff_power
= new struct power
**[dim
];
138 for (int i
= 0; i
< dim
; ++i
)
139 coeff_power
[i
] = new struct power
*[dim
];
142 void vertex_cone::init(const mat_ZZ
&rays
, Param_Vertices
*V
,
145 unsigned nparam
= V
->Vertex
->NbColumns
- 2;
146 this->max_power
= max_power
;
148 for (int i
= 0; i
< dim
; ++i
)
149 zz2values(rays
[i
], coeff
[i
]->p
);
150 qsort(coeff
, dim
, sizeof(Vector
*), pos_cmp
);
152 for (int i
= 0; i
< dim
; ++i
) {
153 for (int j
= 0; j
< dim
; ++j
) {
154 if (value_notzero_p(coeff
[i
]->p
[j
]))
155 coeff_power
[i
][j
] = new struct power(coeff
[i
]->p
[j
], max_power
);
157 coeff_power
[i
][j
] = NULL
;
161 for (int i
= 0; i
< dim
; ++i
)
162 Rays
.p
[i
] = coeff
[i
]->p
;
163 Matrix
*T
= Transpose(&Rays
);
164 Matrix
*L
= relative_coordinates(V
, T
);
167 for (int i
= 0; i
< dim
; ++i
)
168 E_vertex
[i
] = ceiling(L
->p
[i
], V
->Vertex
->p
[0][nparam
+1], nparam
, NULL
);
171 for (int j
= 0; j
< dim
; ++j
) {
172 bernoulli_t
[j
] = new evalue
*[max_power
];
173 for (int k
= 0; k
< max_power
; ++k
)
174 bernoulli_t
[j
][k
] = NULL
;
179 * Returns b(n, E_vertex[i])
181 const evalue
*vertex_cone::get_bernoulli(int n
, int i
)
184 if (!bernoulli_t
[i
][n
-1]) {
185 struct poly_list
*bernoulli
= bernoulli_compute(n
);
186 bernoulli_t
[i
][n
-1] = evalue_polynomial(bernoulli
->poly
[n
],
189 return bernoulli_t
[i
][n
-1];
192 void vertex_cone::clear()
194 for (int i
= 0; i
< dim
; ++i
)
196 evalue_free(E_vertex
[i
]);
198 for (int i
= 0; i
< dim
; ++i
) {
199 for (int j
= 0; j
< max_power
; ++j
) {
200 if (bernoulli_t
[i
][j
])
201 evalue_free(bernoulli_t
[i
][j
]);
203 delete [] bernoulli_t
[i
];
206 for (int i
= 0; i
< dim
; ++i
) {
207 for (int j
= 0; j
< dim
; ++j
)
208 if (coeff_power
[i
][j
])
209 delete coeff_power
[i
][j
];
213 struct todd_product
{
216 /* The non-zero coefficients in the rays of the vertex cone */
217 vector
< vector
<int> > mask
;
218 /* For each ray, the power of each variable it contributes */
219 vector
< vector
<int> > selected
;
220 /* The powers of each variable that still need to be selected */
222 /* For each variable, the last ray that has a non-zero coefficient */
223 vector
<int> last_level
;
225 HASH_MAP
<const vector
<int>, const evalue
*> cache
;
227 todd_product(vertex_cone
&vc
);
228 evalue
*add(evalue
*sum
);
229 const evalue
*get_coefficient(const vector
<int> &powers
);
232 HASH_MAP
<const vector
<int>, const evalue
*>::iterator j
;
233 for (j
= cache
.begin(); j
!= cache
.end(); ++j
)
235 evalue_free(const_cast<evalue
*>((*j
).second
));
239 todd_product::todd_product(vertex_cone
&vc
) : vc(vc
)
242 for (int i
= 0; i
< dim
; ++i
) {
243 mask
.push_back(vector
<int>(dim
));
244 selected
.push_back(vector
<int>(dim
));
246 last_level
= vector
<int>(dim
);
247 for (int i
= 0; i
< dim
; ++i
) {
248 for (int j
= 0; j
< dim
; ++j
) {
249 if (vc
.coeff_power
[i
][j
]) {
257 void multinomial(const vector
<int> &k
, Value
*m
)
261 for (int i
= 0; i
< k
.size(); ++i
) {
265 value_multiply(*m
, *m
, *binomial(s
, k
[i
]));
269 /* Add coefficient of selected powers of variables to sum
270 * and return the result.
271 * The contribution of each ray j of the vertex cone is
274 * b(\sum k, \ceil{v}) ( k_1, \ldots, k_n ) c_1^{k_1} \cdots c_n^{k_n}
276 * with k_i the selected powers, c_i the coefficients of the ray
277 * and \ceil{v} the coordinate E_vertex[j] corresponding to the ray.
279 evalue
*todd_product::add(evalue
*sum
)
282 for (int i
= 0; i
< dim
; ++i
) {
284 evalue
*f
= ALLOC(evalue
);
286 evalue_set_si(f
, 1, 1);
287 for (int j
= 0; j
< dim
; ++j
) {
290 value_multiply(f
->x
.n
, f
->x
.n
,
291 *(*vc
.coeff_power
[i
][j
])[selected
[i
][j
]]);
292 value_multiply(f
->d
, f
->d
, *factorial(selected
[i
][j
]));
296 emul(vc
.get_bernoulli(s
, i
), f
);
313 static int first_non_zero(const vector
<int>& row
)
315 for (int i
= 0; i
< row
.size(); ++i
)
321 /* Return coefficient of the term with exponents powers by
322 * iterating over all combinations of exponents for each ray
323 * that sum up to the given exponents.
325 const evalue
*todd_product::get_coefficient(const vector
<int> &powers
)
329 HASH_MAP
<const vector
<int>, const evalue
*>::iterator i
;
330 i
= cache
.find(powers
);
331 if (i
!= cache
.end())
334 for (int i
= 0; i
< vc
.dim
; ++i
)
335 for (int j
= 0; j
< vc
.dim
; ++j
)
339 int nz
= first_non_zero(left
);
340 int level
= last_level
[nz
];
343 if (mask
[level
][p
] && left
[p
] > 0) {
344 selected
[level
][p
]++;
346 /* Fill out remaining powers and make sure we backtrack from
347 * the right position.
349 for (int i
= 0; i
< vc
.dim
; ++i
) {
352 selected
[last_level
[i
]][i
] += left
[i
];
354 if (last_level
[i
] >= level
) {
355 level
= last_level
[i
];
362 if (selected
[level
][p
]) {
363 left
[p
] += selected
[level
][p
];
364 selected
[level
][p
] = 0;
375 /* Maintains the coefficients of the reciprocals of the
376 * (negated) rays of the vertex cone vc.
381 /* can_borrow_from[i][j] = 1 if there is a ray
382 * with first non-zero coefficient i and a subsequent
383 * non-zero coefficient j.
385 vector
< vector
<int> > can_borrow_from
;
386 /* Total exponent that a variable can borrow from subsequent vars */
387 vector
<int> can_borrow
;
388 /* has_borrowed_from[i][j] is the exponent borrowed by i from j */
389 vector
< vector
<int> > has_borrowed_from
;
390 /* Total exponent borrowed from subsequent vars */
391 vector
<int> has_borrowed
;
392 /* The last variable that can borrow from subsequent vars */
395 /* Position of the first non-zero coefficient in each ray. */
398 /* Power without any "borrowing" */
399 vector
<int> base_power
;
400 /* Power after "borrowing" */
403 /* The non-zero coefficients in the rays of the vertex cone,
406 vector
< vector
<int> > mask
;
407 /* For each ray, the (positive) power of each variable it contributes */
408 vector
< vector
<int> > selected
;
409 /* The powers of each variable that still need to be selected */
412 HASH_MAP
<const vector
<int>, const evalue
*> cache
;
414 reciprocal(vertex_cone
&vc
);
415 void start(vector
<int> &power
);
418 evalue
*add(evalue
*sum
);
419 const evalue
*get_coefficient();
421 HASH_MAP
<const vector
<int>, const evalue
*>::iterator j
;
422 for (j
= cache
.begin(); j
!= cache
.end(); ++j
)
424 evalue_free(const_cast<evalue
*>((*j
).second
));
428 reciprocal::reciprocal(vertex_cone
&vc
) : vc(vc
)
430 for (int i
= 0; i
< vc
.dim
; ++i
) {
431 can_borrow_from
.push_back(vector
<int>(vc
.dim
));
432 has_borrowed_from
.push_back(vector
<int>(vc
.dim
));
433 mask
.push_back(vector
<int>(vc
.dim
));
434 selected
.push_back(vector
<int>(vc
.dim
));
436 can_borrow
= vector
<int>(vc
.dim
);
437 has_borrowed
= vector
<int>(vc
.dim
);
438 neg
= vector
<int>(vc
.dim
);
439 left
= vector
<int>(vc
.dim
);
441 for (int i
= 0; i
< vc
.dim
; ++i
) {
442 int pos
= First_Non_Zero(vc
.coeff
[i
]->p
, vc
.coeff
[i
]->Size
);
444 for (int j
= pos
+1; j
< vc
.dim
; ++j
)
445 if (value_notzero_p(vc
.coeff
[i
]->p
[j
])) {
447 can_borrow_from
[neg
[i
]][j
] = 1;
452 /* Initialize power to the exponent of the todd product
453 * required to compute the coefficient in the full product
454 * of the term with exponent req_power, without any
457 void reciprocal::start(vector
<int> &req_power
)
460 for (int j
= 0; j
< vc
.dim
; ++j
)
466 for (int i
= 0; i
< vc
.dim
; ++i
) {
469 for (int j
= i
+1; j
< vc
.dim
; ++j
) {
470 has_borrowed_from
[i
][j
] = 0;
471 if (can_borrow_from
[i
][j
])
472 can_borrow
[i
] += power
[j
];
479 /* Set power to the next exponent of the todd product required
480 * and return 1 as long as there is any such exponent left.
482 int reciprocal::next()
486 if (has_borrowed
[p
] < can_borrow
[p
]) {
488 for (j
= p
+1; j
< vc
.dim
; ++j
)
489 if (can_borrow_from
[p
][j
]) {
492 else if (has_borrowed_from
[p
][j
]) {
493 power
[j
] += has_borrowed_from
[p
][j
];
494 power
[p
] -= has_borrowed_from
[p
][j
];
495 has_borrowed
[p
] -= has_borrowed_from
[p
][j
];
496 has_borrowed_from
[p
][j
] = 0;
500 has_borrowed_from
[p
][j
]++;
507 if (has_borrowed
[p
]) {
508 for (int j
= p
+1; j
< vc
.dim
; ++j
)
509 if (has_borrowed_from
[p
][j
]) {
510 power
[j
] += has_borrowed_from
[p
][j
];
511 has_borrowed_from
[p
][j
] = 0;
513 power
[p
] -= has_borrowed
[p
];
521 /* Add coefficient of selected powers of variables to sum
522 * and return the result.
523 * The contribution of each ray j of the vertex cone is
526 * ( k_{f+1}, \ldots, k_n ) (-1)^{K+1}
527 * c_f^{-K-1} c_{f+1}^{k_{f+1}} \cdots c_n^{k_n}
529 * K = \sum_{i=f+1}^n k_i
531 evalue
*reciprocal::add(evalue
*sum
)
534 for (int i
= 0; i
< vc
.dim
; ++i
) {
535 evalue
*c
= ALLOC(evalue
);
538 value_set_si(c
->d
, 1);
539 multinomial(selected
[i
], &c
->x
.n
);
541 for (int j
= 0; j
< vc
.dim
; ++j
) {
542 if (selected
[i
][j
] == 0)
544 value_multiply(c
->x
.n
, c
->x
.n
,
545 *(*vc
.coeff_power
[i
][j
])[selected
[i
][j
]]);
548 value_multiply(c
->d
, c
->d
, *(*vc
.coeff_power
[i
][neg
[i
]])[s
+1]);
550 value_oppose(c
->x
.n
, c
->x
.n
);
551 if (value_neg_p(c
->d
)) {
552 value_oppose(c
->d
, c
->d
);
553 value_oppose(c
->x
.n
, c
->x
.n
);
571 /* Return coefficient of the term with exponents powers by
572 * iterating over all combinations of exponents for each ray
573 * that sum up to the given exponents.
575 const evalue
*reciprocal::get_coefficient()
579 for (int j
= 0; j
< vc
.dim
; ++j
)
580 left
[j
] = base_power
[j
] - power
[j
];
582 HASH_MAP
<const vector
<int>, const evalue
*>::iterator i
;
583 i
= cache
.find(left
);
584 if (i
!= cache
.end())
587 int nz
= first_non_zero(left
);
589 return cache
[power
] = add(c
);
593 for (int i
= 0; i
< vc
.dim
; ++i
)
594 for (int j
= 0; j
< vc
.dim
; ++j
)
597 int level
= vc
.dim
-1;
600 int nz
= first_non_zero(left
);
601 if (nz
< neg
[level
] || (nz
== neg
[level
] && left
[nz
] > 0)) {
602 assert(p
== vc
.dim
-1);
606 if (nz
== neg
[level
] && mask
[level
][p
]) {
607 selected
[level
][p
]++;
610 int nz
= first_non_zero(left
);
619 if (selected
[level
][p
]) {
620 left
[p
] += selected
[level
][p
];
621 left
[neg
[level
]] -= selected
[level
][p
];
622 selected
[level
][p
] = 0;
634 /* A term in the input polynomial */
640 static void collect_terms_r(vector
<struct term
> &terms
, vector
<int> &powers
,
641 const evalue
*polynomial
, unsigned nvar
)
643 if (EVALUE_IS_ZERO(*polynomial
))
646 if (value_zero_p(polynomial
->d
))
647 assert(polynomial
->x
.p
->type
== ::polynomial
);
648 if (value_notzero_p(polynomial
->d
) || polynomial
->x
.p
->pos
> nvar
) {
651 t
.coeff
= polynomial
;
656 for (int i
= polynomial
->x
.p
->size
-1; i
>= 0; --i
) {
657 powers
[polynomial
->x
.p
->pos
-1] = i
;
658 collect_terms_r(terms
, powers
, &polynomial
->x
.p
->arr
[i
], nvar
);
662 /* Expand "polynomial" as a sum of powers of the "nvar" variables,
663 * collect the terms in "terms" and return the maximal total degree.
665 static unsigned collect_terms(vector
<struct term
> &terms
,
666 const evalue
*polynomial
, unsigned nvar
)
668 vector
<int> powers(nvar
);
669 for (int i
= 0; i
< nvar
; ++i
)
671 collect_terms_r(terms
, powers
, polynomial
, nvar
);
673 unsigned max_degree
= 0;
674 for (int i
= 0; i
< terms
.size(); ++i
) {
676 for (int j
= 0; j
< nvar
; ++j
)
677 sum
+= terms
[i
].powers
[j
];
678 if (sum
> max_degree
)
685 static void dump_terms(const vector<struct term> &terms)
687 for (int i = 0; i < terms.size(); ++i) {
688 cerr << terms[i].powers;
689 print_evalue(stderr, terms[i].coeff, test);
694 struct laurent_summator
: public signed_cone_consumer
,
695 public vertex_decomposer
{
696 const evalue
*polynomial
;
699 vector
<struct term
> terms
;
703 laurent_summator(const evalue
*e
, unsigned dim
, Param_Polyhedron
*PP
) :
704 polynomial(e
), dim(dim
), vertex_decomposer(PP
, *this),
706 max_power
= dim
+ collect_terms(terms
, polynomial
, dim
);
709 ~laurent_summator() {
713 virtual void handle(const signed_cone
& sc
, barvinok_options
*options
);
716 static int first_non_zero(const vec_ZZ
& row
)
718 for (int i
= 0; i
< row
.length(); ++i
)
724 void laurent_summator::handle(const signed_cone
& sc
, barvinok_options
*options
)
728 vc
.init(sc
.rays
, V
, max_power
);
729 reciprocal
recip(vc
);
731 for (int i
= 0; i
< terms
.size(); ++i
) {
732 recip
.start(terms
[i
].powers
);
734 const evalue
*c
= recip
.get_coefficient();
738 const evalue
*t
= tp
.get_coefficient(recip
.power
);
740 evalue
*f
= evalue_dup(terms
[i
].coeff
);
743 for (int j
= 0; j
< dim
; ++j
)
744 evalue_mul(f
, *factorial(terms
[i
].powers
[j
]));
745 evalue_shift_variables(f
, -dim
);
754 } while (recip
.next());
759 static evalue
*summate_over_domain(const evalue
*e
, unsigned nvar
,
761 struct barvinok_options
*options
)
764 Param_Polyhedron
*PP
;
765 struct evalue_section
*s
;
770 U
= Universe_Polyhedron(D
->Dimension
- nvar
);
771 PP
= Polyhedron2Param_Polyhedron(D
, U
, options
);
773 for (nd
= 0, PD
= PP
->D
; PD
; ++nd
, PD
= PD
->next
);
774 s
= ALLOCN(struct evalue_section
, nd
);
776 TC
= true_context(D
, U
, options
->MaxRays
);
777 FORALL_REDUCED_DOMAIN(PP
, TC
, nd
, options
, i
, PD
, rVD
)
779 laurent_summator
ls(e
, nvar
, PP
);
781 FORALL_PVertex_in_ParamPolyhedron(V
, PD
, PP
) // _i internal counter
782 ls
.decompose_at_vertex(V
, _i
, options
);
783 END_FORALL_PVertex_in_ParamPolyhedron
;
788 END_FORALL_REDUCED_DOMAIN
791 Param_Polyhedron_Free(PP
);
793 sum
= evalue_from_section_array(s
, nd
);
799 evalue
*laurent_summate(evalue
*e
, unsigned nvar
,
800 struct barvinok_options
*options
)
806 if (nvar
== 0 || EVALUE_IS_ZERO(*e
))
807 return evalue_dup(e
);
809 assert(value_zero_p(e
->d
));
810 assert(e
->x
.p
->type
== partition
);
814 for (i
= 0; i
< e
->x
.p
->size
/2; ++i
) {
816 t
= summate_over_domain(&e
->x
.p
->arr
[2*i
+1], nvar
,
817 EVALUE_DOMAIN(e
->x
.p
->arr
[2*i
]), options
);