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 #if defined HAVE_UNORDERED_MAP
22 #include <unordered_map>
24 #define HASH_MAP std::unordered_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
)
40 #elif defined HAVE_GNUCXX_HASHMAP
42 #include <ext/hash_map>
44 #define HASH_MAP __gnu_cxx::hash_map
48 template<> struct hash
< std::vector
<int> >
50 size_t operator()( const std::vector
<int>& x
) const
52 unsigned long __h
= 0;
53 for (int i
= 0; i
< x
.size(); ++i
)
62 #warning "no hash_map available"
64 #define HASH_MAP std::map
68 #define ALLOC(type) (type*)malloc(sizeof(type))
69 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
71 static ostream
& operator<< (ostream
& os
, const vector
<int> & v
)
72 __attribute__((unused
));
73 static ostream
& operator<< (ostream
& os
, const vector
<int> & v
)
76 for (int i
= 0; i
< v
.size(); ++i
) {
88 /* The non-zero coefficients in the rays of the vertex cone */
89 vector
< vector
<int> > mask
;
90 /* For each ray, the power of each variable it contributes */
91 vector
< vector
<int> > selected
;
92 /* The powers of each variable that still need to be selected */
94 /* For each variable, the last ray that has a non-zero coefficient */
95 vector
<int> last_level
;
97 HASH_MAP
<vector
<int>, const evalue
*> cache
;
99 todd_product(vertex_cone
&vc
);
100 evalue
*add(evalue
*sum
);
101 const evalue
*get_coefficient(const vector
<int> &powers
);
104 HASH_MAP
<vector
<int>, const evalue
*>::iterator j
;
105 for (j
= cache
.begin(); j
!= cache
.end(); ++j
)
107 evalue_free(const_cast<evalue
*>((*j
).second
));
111 todd_product::todd_product(vertex_cone
&vc
) : vc(vc
)
114 for (int i
= 0; i
< dim
; ++i
) {
115 mask
.push_back(vector
<int>(dim
));
116 selected
.push_back(vector
<int>(dim
));
118 last_level
= vector
<int>(dim
);
119 for (int i
= 0; i
< dim
; ++i
) {
120 for (int j
= 0; j
< dim
; ++j
) {
121 if (vc
.coeff_power
[i
][j
]) {
129 void multinomial(const vector
<int> &k
, Value
*m
)
133 for (int i
= 0; i
< k
.size(); ++i
) {
137 value_multiply(*m
, *m
, *binomial(s
, k
[i
]));
141 /* Add coefficient of selected powers of variables to sum
142 * and return the result.
143 * The contribution of each ray j of the vertex cone is
146 * b(\sum k, \ceil{v}) ( k_1, \ldots, k_n ) c_1^{k_1} \cdots c_n^{k_n}
148 * with k_i the selected powers, c_i the coefficients of the ray
149 * and \ceil{v} the coordinate E_vertex[j] corresponding to the ray.
151 evalue
*todd_product::add(evalue
*sum
)
154 for (int i
= 0; i
< dim
; ++i
) {
156 evalue
*f
= ALLOC(evalue
);
158 evalue_set_si(f
, 1, 1);
159 for (int j
= 0; j
< dim
; ++j
) {
162 value_multiply(f
->x
.n
, f
->x
.n
,
163 *(*vc
.coeff_power
[i
][j
])[selected
[i
][j
]]);
164 value_multiply(f
->d
, f
->d
, *factorial(selected
[i
][j
]));
168 emul(vc
.get_bernoulli(s
, i
), f
);
185 static int first_non_zero(const vector
<int>& row
)
187 for (int i
= 0; i
< row
.size(); ++i
)
193 /* Return coefficient of the term with exponents powers by
194 * iterating over all combinations of exponents for each ray
195 * that sum up to the given exponents.
197 const evalue
*todd_product::get_coefficient(const vector
<int> &powers
)
201 HASH_MAP
<vector
<int>, const evalue
*>::iterator i
;
202 i
= cache
.find(powers
);
203 if (i
!= cache
.end())
206 for (int i
= 0; i
< vc
.dim
; ++i
)
207 for (int j
= 0; j
< vc
.dim
; ++j
)
211 int nz
= first_non_zero(left
);
212 int level
= last_level
[nz
];
215 if (mask
[level
][p
] && left
[p
] > 0) {
216 selected
[level
][p
]++;
218 /* Fill out remaining powers and make sure we backtrack from
219 * the right position.
221 for (int i
= 0; i
< vc
.dim
; ++i
) {
224 selected
[last_level
[i
]][i
] += left
[i
];
226 if (last_level
[i
] >= level
) {
227 level
= last_level
[i
];
234 if (selected
[level
][p
]) {
235 left
[p
] += selected
[level
][p
];
236 selected
[level
][p
] = 0;
247 /* Maintains the coefficients of the reciprocals of the
248 * (negated) rays of the vertex cone vc.
253 /* can_borrow_from[i][j] = 1 if there is a ray
254 * with first non-zero coefficient i and a subsequent
255 * non-zero coefficient j.
257 vector
< vector
<int> > can_borrow_from
;
258 /* Total exponent that a variable can borrow from subsequent vars */
259 vector
<int> can_borrow
;
260 /* has_borrowed_from[i][j] is the exponent borrowed by i from j */
261 vector
< vector
<int> > has_borrowed_from
;
262 /* Total exponent borrowed from subsequent vars */
263 vector
<int> has_borrowed
;
264 /* The last variable that can borrow from subsequent vars */
267 /* Position of the first non-zero coefficient in each ray. */
270 /* Power without any "borrowing" */
271 vector
<int> base_power
;
272 /* Power after "borrowing" */
275 /* The non-zero coefficients in the rays of the vertex cone,
278 vector
< vector
<int> > mask
;
279 /* For each ray, the (positive) power of each variable it contributes */
280 vector
< vector
<int> > selected
;
281 /* The powers of each variable that still need to be selected */
284 HASH_MAP
<vector
<int>, const evalue
*> cache
;
286 reciprocal(vertex_cone
&vc
);
287 void start(vector
<int> &power
);
290 evalue
*add(evalue
*sum
);
291 const evalue
*get_coefficient();
293 HASH_MAP
<vector
<int>, const evalue
*>::iterator j
;
294 for (j
= cache
.begin(); j
!= cache
.end(); ++j
)
296 evalue_free(const_cast<evalue
*>((*j
).second
));
300 reciprocal::reciprocal(vertex_cone
&vc
) : vc(vc
)
302 for (int i
= 0; i
< vc
.dim
; ++i
) {
303 can_borrow_from
.push_back(vector
<int>(vc
.dim
));
304 has_borrowed_from
.push_back(vector
<int>(vc
.dim
));
305 mask
.push_back(vector
<int>(vc
.dim
));
306 selected
.push_back(vector
<int>(vc
.dim
));
308 can_borrow
= vector
<int>(vc
.dim
);
309 has_borrowed
= vector
<int>(vc
.dim
);
310 neg
= vector
<int>(vc
.dim
);
311 left
= vector
<int>(vc
.dim
);
313 for (int i
= 0; i
< vc
.dim
; ++i
) {
314 int pos
= First_Non_Zero(vc
.coeff
[i
]->p
, vc
.coeff
[i
]->Size
);
316 for (int j
= pos
+1; j
< vc
.dim
; ++j
)
317 if (value_notzero_p(vc
.coeff
[i
]->p
[j
])) {
319 can_borrow_from
[neg
[i
]][j
] = 1;
324 /* Initialize power to the exponent of the todd product
325 * required to compute the coefficient in the full product
326 * of the term with exponent req_power, without any
329 void reciprocal::start(vector
<int> &req_power
)
332 for (int j
= 0; j
< vc
.dim
; ++j
)
338 for (int i
= 0; i
< vc
.dim
; ++i
) {
341 for (int j
= i
+1; j
< vc
.dim
; ++j
) {
342 has_borrowed_from
[i
][j
] = 0;
343 if (can_borrow_from
[i
][j
])
344 can_borrow
[i
] += power
[j
];
351 /* Set power to the next exponent of the todd product required
352 * and return 1 as long as there is any such exponent left.
354 int reciprocal::next()
358 if (has_borrowed
[p
] < can_borrow
[p
]) {
360 for (j
= p
+1; j
< vc
.dim
; ++j
)
361 if (can_borrow_from
[p
][j
]) {
364 else if (has_borrowed_from
[p
][j
]) {
365 power
[j
] += has_borrowed_from
[p
][j
];
366 power
[p
] -= has_borrowed_from
[p
][j
];
367 has_borrowed
[p
] -= has_borrowed_from
[p
][j
];
368 has_borrowed_from
[p
][j
] = 0;
372 has_borrowed_from
[p
][j
]++;
379 if (has_borrowed
[p
]) {
380 for (int j
= p
+1; j
< vc
.dim
; ++j
)
381 if (has_borrowed_from
[p
][j
]) {
382 power
[j
] += has_borrowed_from
[p
][j
];
383 has_borrowed_from
[p
][j
] = 0;
385 power
[p
] -= has_borrowed
[p
];
393 /* Add coefficient of selected powers of variables to sum
394 * and return the result.
395 * The contribution of each ray j of the vertex cone is
398 * ( k_{f+1}, \ldots, k_n ) (-1)^{K+1}
399 * c_f^{-K-1} c_{f+1}^{k_{f+1}} \cdots c_n^{k_n}
401 * K = \sum_{i=f+1}^n k_i
403 evalue
*reciprocal::add(evalue
*sum
)
406 for (int i
= 0; i
< vc
.dim
; ++i
) {
407 evalue
*c
= ALLOC(evalue
);
410 value_set_si(c
->d
, 1);
411 multinomial(selected
[i
], &c
->x
.n
);
413 for (int j
= 0; j
< vc
.dim
; ++j
) {
414 if (selected
[i
][j
] == 0)
416 value_multiply(c
->x
.n
, c
->x
.n
,
417 *(*vc
.coeff_power
[i
][j
])[selected
[i
][j
]]);
420 value_multiply(c
->d
, c
->d
, *(*vc
.coeff_power
[i
][neg
[i
]])[s
+1]);
422 value_oppose(c
->x
.n
, c
->x
.n
);
423 if (value_neg_p(c
->d
)) {
424 value_oppose(c
->d
, c
->d
);
425 value_oppose(c
->x
.n
, c
->x
.n
);
443 /* Return coefficient of the term with exponents powers by
444 * iterating over all combinations of exponents for each ray
445 * that sum up to the given exponents.
447 const evalue
*reciprocal::get_coefficient()
451 for (int j
= 0; j
< vc
.dim
; ++j
)
452 left
[j
] = base_power
[j
] - power
[j
];
454 HASH_MAP
<vector
<int>, const evalue
*>::iterator i
;
455 i
= cache
.find(left
);
456 if (i
!= cache
.end())
459 int nz
= first_non_zero(left
);
461 return cache
[power
] = add(c
);
465 for (int i
= 0; i
< vc
.dim
; ++i
)
466 for (int j
= 0; j
< vc
.dim
; ++j
)
469 int level
= vc
.dim
-1;
472 int nz
= first_non_zero(left
);
473 if (nz
< neg
[level
] || (nz
== neg
[level
] && left
[nz
] > 0)) {
474 assert(p
== vc
.dim
-1);
478 if (nz
== neg
[level
] && mask
[level
][p
]) {
479 selected
[level
][p
]++;
482 int nz
= first_non_zero(left
);
485 else if (left
[nz
] < 0) {
491 if (selected
[level
][p
]) {
492 left
[p
] += selected
[level
][p
];
493 left
[neg
[level
]] -= selected
[level
][p
];
494 selected
[level
][p
] = 0;
506 struct laurent_summator_old
: public signed_cone_consumer
,
507 public vertex_decomposer
{
508 const evalue
*polynomial
;
511 param_polynomial poly
;
515 laurent_summator_old(const evalue
*e
, unsigned dim
, Param_Polyhedron
*PP
) :
516 vertex_decomposer(PP
, *this), polynomial(e
), dim(dim
),
517 vc(dim
), poly(e
, dim
) {
518 max_power
= dim
+ poly
.degree();
521 ~laurent_summator_old() {
525 virtual void handle(const signed_cone
& sc
, barvinok_options
*options
);
528 void laurent_summator_old::handle(const signed_cone
& sc
, barvinok_options
*options
)
532 vc
.init(sc
.rays
, V
, max_power
);
533 reciprocal
recip(vc
);
535 for (int i
= 0; i
< poly
.terms
.size(); ++i
) {
536 recip
.start(poly
.terms
[i
].powers
);
538 const evalue
*c
= recip
.get_coefficient();
542 const evalue
*t
= tp
.get_coefficient(recip
.power
);
544 evalue
*f
= evalue_dup(poly
.terms
[i
].coeff
);
547 for (int j
= 0; j
< dim
; ++j
)
548 evalue_mul(f
, *factorial(poly
.terms
[i
].powers
[j
]));
549 evalue_shift_variables(f
, 0, -dim
);
558 } while (recip
.next());
563 evalue
*laurent_summate_old(Polyhedron
*P
, evalue
*e
, unsigned nvar
,
564 struct barvinok_options
*options
)
567 Param_Polyhedron
*PP
;
568 struct evalue_section
*s
;
573 U
= Universe_Polyhedron(P
->Dimension
- nvar
);
574 PP
= Polyhedron2Param_Polyhedron(P
, U
, options
);
576 for (nd
= 0, PD
= PP
->D
; PD
; ++nd
, PD
= PD
->next
);
577 s
= ALLOCN(struct evalue_section
, nd
);
579 TC
= true_context(P
, U
, options
->MaxRays
);
580 FORALL_REDUCED_DOMAIN(PP
, TC
, nd
, options
, i
, PD
, rVD
)
582 laurent_summator_old
ls(e
, nvar
, PP
);
584 FORALL_PVertex_in_ParamPolyhedron(V
, PD
, PP
) // _i internal counter
585 ls
.decompose_at_vertex(V
, _i
, options
);
586 END_FORALL_PVertex_in_ParamPolyhedron
;
591 END_FORALL_REDUCED_DOMAIN
594 Param_Polyhedron_Free(PP
);
596 sum
= evalue_from_section_array(s
, nd
);