4 #include <barvinok/options.h>
6 #include "conversion.h"
7 #include "decomposer.h"
8 #include "laurent_old.h"
9 #include "param_polynomial.h"
10 #include "param_util.h"
11 #include "reduce_domain.h"
12 #include "vertex_cone.h"
20 #ifdef HAVE_GNUCXX_HASHMAP
22 #include <ext/hash_map>
24 #define HASH_MAP __gnu_cxx::hash_map
28 template<> struct hash
< std::vector
<int> >
30 size_t operator()( const std::vector
<int>& x
) const
32 unsigned long __h
= 0;
33 for (int i
= 0; i
< x
.size(); ++i
)
42 #warning "no hash_map available"
44 #define HASH_MAP std::map
48 #define ALLOC(type) (type*)malloc(sizeof(type))
49 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
51 static ostream
& operator<< (ostream
& os
, const vector
<int> & v
)
54 for (int i
= 0; i
< v
.size(); ++i
) {
66 /* The non-zero coefficients in the rays of the vertex cone */
67 vector
< vector
<int> > mask
;
68 /* For each ray, the power of each variable it contributes */
69 vector
< vector
<int> > selected
;
70 /* The powers of each variable that still need to be selected */
72 /* For each variable, the last ray that has a non-zero coefficient */
73 vector
<int> last_level
;
75 HASH_MAP
<vector
<int>, const evalue
*> cache
;
77 todd_product(vertex_cone
&vc
);
78 evalue
*add(evalue
*sum
);
79 const evalue
*get_coefficient(const vector
<int> &powers
);
82 HASH_MAP
<vector
<int>, const evalue
*>::iterator j
;
83 for (j
= cache
.begin(); j
!= cache
.end(); ++j
)
85 evalue_free(const_cast<evalue
*>((*j
).second
));
89 todd_product::todd_product(vertex_cone
&vc
) : vc(vc
)
92 for (int i
= 0; i
< dim
; ++i
) {
93 mask
.push_back(vector
<int>(dim
));
94 selected
.push_back(vector
<int>(dim
));
96 last_level
= vector
<int>(dim
);
97 for (int i
= 0; i
< dim
; ++i
) {
98 for (int j
= 0; j
< dim
; ++j
) {
99 if (vc
.coeff_power
[i
][j
]) {
107 void multinomial(const vector
<int> &k
, Value
*m
)
111 for (int i
= 0; i
< k
.size(); ++i
) {
115 value_multiply(*m
, *m
, *binomial(s
, k
[i
]));
119 /* Add coefficient of selected powers of variables to sum
120 * and return the result.
121 * The contribution of each ray j of the vertex cone is
124 * b(\sum k, \ceil{v}) ( k_1, \ldots, k_n ) c_1^{k_1} \cdots c_n^{k_n}
126 * with k_i the selected powers, c_i the coefficients of the ray
127 * and \ceil{v} the coordinate E_vertex[j] corresponding to the ray.
129 evalue
*todd_product::add(evalue
*sum
)
132 for (int i
= 0; i
< dim
; ++i
) {
134 evalue
*f
= ALLOC(evalue
);
136 evalue_set_si(f
, 1, 1);
137 for (int j
= 0; j
< dim
; ++j
) {
140 value_multiply(f
->x
.n
, f
->x
.n
,
141 *(*vc
.coeff_power
[i
][j
])[selected
[i
][j
]]);
142 value_multiply(f
->d
, f
->d
, *factorial(selected
[i
][j
]));
146 emul(vc
.get_bernoulli(s
, i
), f
);
163 static int first_non_zero(const vector
<int>& row
)
165 for (int i
= 0; i
< row
.size(); ++i
)
171 /* Return coefficient of the term with exponents powers by
172 * iterating over all combinations of exponents for each ray
173 * that sum up to the given exponents.
175 const evalue
*todd_product::get_coefficient(const vector
<int> &powers
)
179 HASH_MAP
<vector
<int>, const evalue
*>::iterator i
;
180 i
= cache
.find(powers
);
181 if (i
!= cache
.end())
184 for (int i
= 0; i
< vc
.dim
; ++i
)
185 for (int j
= 0; j
< vc
.dim
; ++j
)
189 int nz
= first_non_zero(left
);
190 int level
= last_level
[nz
];
193 if (mask
[level
][p
] && left
[p
] > 0) {
194 selected
[level
][p
]++;
196 /* Fill out remaining powers and make sure we backtrack from
197 * the right position.
199 for (int i
= 0; i
< vc
.dim
; ++i
) {
202 selected
[last_level
[i
]][i
] += left
[i
];
204 if (last_level
[i
] >= level
) {
205 level
= last_level
[i
];
212 if (selected
[level
][p
]) {
213 left
[p
] += selected
[level
][p
];
214 selected
[level
][p
] = 0;
225 /* Maintains the coefficients of the reciprocals of the
226 * (negated) rays of the vertex cone vc.
231 /* can_borrow_from[i][j] = 1 if there is a ray
232 * with first non-zero coefficient i and a subsequent
233 * non-zero coefficient j.
235 vector
< vector
<int> > can_borrow_from
;
236 /* Total exponent that a variable can borrow from subsequent vars */
237 vector
<int> can_borrow
;
238 /* has_borrowed_from[i][j] is the exponent borrowed by i from j */
239 vector
< vector
<int> > has_borrowed_from
;
240 /* Total exponent borrowed from subsequent vars */
241 vector
<int> has_borrowed
;
242 /* The last variable that can borrow from subsequent vars */
245 /* Position of the first non-zero coefficient in each ray. */
248 /* Power without any "borrowing" */
249 vector
<int> base_power
;
250 /* Power after "borrowing" */
253 /* The non-zero coefficients in the rays of the vertex cone,
256 vector
< vector
<int> > mask
;
257 /* For each ray, the (positive) power of each variable it contributes */
258 vector
< vector
<int> > selected
;
259 /* The powers of each variable that still need to be selected */
262 HASH_MAP
<vector
<int>, const evalue
*> cache
;
264 reciprocal(vertex_cone
&vc
);
265 void start(vector
<int> &power
);
268 evalue
*add(evalue
*sum
);
269 const evalue
*get_coefficient();
271 HASH_MAP
<vector
<int>, const evalue
*>::iterator j
;
272 for (j
= cache
.begin(); j
!= cache
.end(); ++j
)
274 evalue_free(const_cast<evalue
*>((*j
).second
));
278 reciprocal::reciprocal(vertex_cone
&vc
) : vc(vc
)
280 for (int i
= 0; i
< vc
.dim
; ++i
) {
281 can_borrow_from
.push_back(vector
<int>(vc
.dim
));
282 has_borrowed_from
.push_back(vector
<int>(vc
.dim
));
283 mask
.push_back(vector
<int>(vc
.dim
));
284 selected
.push_back(vector
<int>(vc
.dim
));
286 can_borrow
= vector
<int>(vc
.dim
);
287 has_borrowed
= vector
<int>(vc
.dim
);
288 neg
= vector
<int>(vc
.dim
);
289 left
= vector
<int>(vc
.dim
);
291 for (int i
= 0; i
< vc
.dim
; ++i
) {
292 int pos
= First_Non_Zero(vc
.coeff
[i
]->p
, vc
.coeff
[i
]->Size
);
294 for (int j
= pos
+1; j
< vc
.dim
; ++j
)
295 if (value_notzero_p(vc
.coeff
[i
]->p
[j
])) {
297 can_borrow_from
[neg
[i
]][j
] = 1;
302 /* Initialize power to the exponent of the todd product
303 * required to compute the coefficient in the full product
304 * of the term with exponent req_power, without any
307 void reciprocal::start(vector
<int> &req_power
)
310 for (int j
= 0; j
< vc
.dim
; ++j
)
316 for (int i
= 0; i
< vc
.dim
; ++i
) {
319 for (int j
= i
+1; j
< vc
.dim
; ++j
) {
320 has_borrowed_from
[i
][j
] = 0;
321 if (can_borrow_from
[i
][j
])
322 can_borrow
[i
] += power
[j
];
329 /* Set power to the next exponent of the todd product required
330 * and return 1 as long as there is any such exponent left.
332 int reciprocal::next()
336 if (has_borrowed
[p
] < can_borrow
[p
]) {
338 for (j
= p
+1; j
< vc
.dim
; ++j
)
339 if (can_borrow_from
[p
][j
]) {
342 else if (has_borrowed_from
[p
][j
]) {
343 power
[j
] += has_borrowed_from
[p
][j
];
344 power
[p
] -= has_borrowed_from
[p
][j
];
345 has_borrowed
[p
] -= has_borrowed_from
[p
][j
];
346 has_borrowed_from
[p
][j
] = 0;
350 has_borrowed_from
[p
][j
]++;
357 if (has_borrowed
[p
]) {
358 for (int j
= p
+1; j
< vc
.dim
; ++j
)
359 if (has_borrowed_from
[p
][j
]) {
360 power
[j
] += has_borrowed_from
[p
][j
];
361 has_borrowed_from
[p
][j
] = 0;
363 power
[p
] -= has_borrowed
[p
];
371 /* Add coefficient of selected powers of variables to sum
372 * and return the result.
373 * The contribution of each ray j of the vertex cone is
376 * ( k_{f+1}, \ldots, k_n ) (-1)^{K+1}
377 * c_f^{-K-1} c_{f+1}^{k_{f+1}} \cdots c_n^{k_n}
379 * K = \sum_{i=f+1}^n k_i
381 evalue
*reciprocal::add(evalue
*sum
)
384 for (int i
= 0; i
< vc
.dim
; ++i
) {
385 evalue
*c
= ALLOC(evalue
);
388 value_set_si(c
->d
, 1);
389 multinomial(selected
[i
], &c
->x
.n
);
391 for (int j
= 0; j
< vc
.dim
; ++j
) {
392 if (selected
[i
][j
] == 0)
394 value_multiply(c
->x
.n
, c
->x
.n
,
395 *(*vc
.coeff_power
[i
][j
])[selected
[i
][j
]]);
398 value_multiply(c
->d
, c
->d
, *(*vc
.coeff_power
[i
][neg
[i
]])[s
+1]);
400 value_oppose(c
->x
.n
, c
->x
.n
);
401 if (value_neg_p(c
->d
)) {
402 value_oppose(c
->d
, c
->d
);
403 value_oppose(c
->x
.n
, c
->x
.n
);
421 /* Return coefficient of the term with exponents powers by
422 * iterating over all combinations of exponents for each ray
423 * that sum up to the given exponents.
425 const evalue
*reciprocal::get_coefficient()
429 for (int j
= 0; j
< vc
.dim
; ++j
)
430 left
[j
] = base_power
[j
] - power
[j
];
432 HASH_MAP
<vector
<int>, const evalue
*>::iterator i
;
433 i
= cache
.find(left
);
434 if (i
!= cache
.end())
437 int nz
= first_non_zero(left
);
439 return cache
[power
] = add(c
);
443 for (int i
= 0; i
< vc
.dim
; ++i
)
444 for (int j
= 0; j
< vc
.dim
; ++j
)
447 int level
= vc
.dim
-1;
450 int nz
= first_non_zero(left
);
451 if (nz
< neg
[level
] || (nz
== neg
[level
] && left
[nz
] > 0)) {
452 assert(p
== vc
.dim
-1);
456 if (nz
== neg
[level
] && mask
[level
][p
]) {
457 selected
[level
][p
]++;
460 int nz
= first_non_zero(left
);
463 else if (left
[nz
] < 0) {
469 if (selected
[level
][p
]) {
470 left
[p
] += selected
[level
][p
];
471 left
[neg
[level
]] -= selected
[level
][p
];
472 selected
[level
][p
] = 0;
484 struct laurent_summator_old
: public signed_cone_consumer
,
485 public vertex_decomposer
{
486 const evalue
*polynomial
;
489 param_polynomial poly
;
493 laurent_summator_old(const evalue
*e
, unsigned dim
, Param_Polyhedron
*PP
) :
494 polynomial(e
), dim(dim
), vertex_decomposer(PP
, *this),
495 vc(dim
), poly(e
, dim
) {
496 max_power
= dim
+ poly
.degree();
499 ~laurent_summator_old() {
503 virtual void handle(const signed_cone
& sc
, barvinok_options
*options
);
506 void laurent_summator_old::handle(const signed_cone
& sc
, barvinok_options
*options
)
510 vc
.init(sc
.rays
, V
, max_power
);
511 reciprocal
recip(vc
);
513 for (int i
= 0; i
< poly
.terms
.size(); ++i
) {
514 recip
.start(poly
.terms
[i
].powers
);
516 const evalue
*c
= recip
.get_coefficient();
520 const evalue
*t
= tp
.get_coefficient(recip
.power
);
522 evalue
*f
= evalue_dup(poly
.terms
[i
].coeff
);
525 for (int j
= 0; j
< dim
; ++j
)
526 evalue_mul(f
, *factorial(poly
.terms
[i
].powers
[j
]));
527 evalue_shift_variables(f
, 0, -dim
);
536 } while (recip
.next());
541 evalue
*laurent_summate_old(Polyhedron
*P
, evalue
*e
, unsigned nvar
,
542 struct barvinok_options
*options
)
545 Param_Polyhedron
*PP
;
546 struct evalue_section
*s
;
551 U
= Universe_Polyhedron(P
->Dimension
- nvar
);
552 PP
= Polyhedron2Param_Polyhedron(P
, U
, options
);
554 for (nd
= 0, PD
= PP
->D
; PD
; ++nd
, PD
= PD
->next
);
555 s
= ALLOCN(struct evalue_section
, nd
);
557 TC
= true_context(P
, U
, options
->MaxRays
);
558 FORALL_REDUCED_DOMAIN(PP
, TC
, nd
, options
, i
, PD
, rVD
)
560 laurent_summator_old
ls(e
, nvar
, PP
);
562 FORALL_PVertex_in_ParamPolyhedron(V
, PD
, PP
) // _i internal counter
563 ls
.decompose_at_vertex(V
, _i
, options
);
564 END_FORALL_PVertex_in_ParamPolyhedron
;
569 END_FORALL_REDUCED_DOMAIN
572 Param_Polyhedron_Free(PP
);
574 sum
= evalue_from_section_array(s
, nd
);