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 #include <unordered_map>
22 #define HASH_MAP std::unordered_map
26 template<> struct hash
< std::vector
<int> >
28 size_t operator()( const std::vector
<int>& x
) const
30 unsigned long __h
= 0;
31 for (int i
= 0; i
< x
.size(); ++i
)
38 #define ALLOC(type) (type*)malloc(sizeof(type))
39 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
41 static ostream
& operator<< (ostream
& os
, const vector
<int> & v
)
42 __attribute__((unused
));
43 static ostream
& operator<< (ostream
& os
, const vector
<int> & v
)
46 for (int i
= 0; i
< v
.size(); ++i
) {
58 /* The non-zero coefficients in the rays of the vertex cone */
59 vector
< vector
<int> > mask
;
60 /* For each ray, the power of each variable it contributes */
61 vector
< vector
<int> > selected
;
62 /* The powers of each variable that still need to be selected */
64 /* For each variable, the last ray that has a non-zero coefficient */
65 vector
<int> last_level
;
67 HASH_MAP
<vector
<int>, const evalue
*> cache
;
69 todd_product(vertex_cone
&vc
);
70 evalue
*add(evalue
*sum
);
71 const evalue
*get_coefficient(const vector
<int> &powers
);
74 HASH_MAP
<vector
<int>, const evalue
*>::iterator j
;
75 for (j
= cache
.begin(); j
!= cache
.end(); ++j
)
77 evalue_free(const_cast<evalue
*>((*j
).second
));
81 todd_product::todd_product(vertex_cone
&vc
) : vc(vc
)
84 for (int i
= 0; i
< dim
; ++i
) {
85 mask
.push_back(vector
<int>(dim
));
86 selected
.push_back(vector
<int>(dim
));
88 last_level
= vector
<int>(dim
);
89 for (int i
= 0; i
< dim
; ++i
) {
90 for (int j
= 0; j
< dim
; ++j
) {
91 if (vc
.coeff_power
[i
][j
]) {
99 void multinomial(const vector
<int> &k
, Value
*m
)
103 for (int i
= 0; i
< k
.size(); ++i
) {
107 value_multiply(*m
, *m
, *binomial(s
, k
[i
]));
111 /* Add coefficient of selected powers of variables to sum
112 * and return the result.
113 * The contribution of each ray j of the vertex cone is
116 * b(\sum k, \ceil{v}) ( k_1, \ldots, k_n ) c_1^{k_1} \cdots c_n^{k_n}
118 * with k_i the selected powers, c_i the coefficients of the ray
119 * and \ceil{v} the coordinate E_vertex[j] corresponding to the ray.
121 evalue
*todd_product::add(evalue
*sum
)
124 for (int i
= 0; i
< dim
; ++i
) {
126 evalue
*f
= ALLOC(evalue
);
128 evalue_set_si(f
, 1, 1);
129 for (int j
= 0; j
< dim
; ++j
) {
132 value_multiply(f
->x
.n
, f
->x
.n
,
133 *(*vc
.coeff_power
[i
][j
])[selected
[i
][j
]]);
134 value_multiply(f
->d
, f
->d
, *factorial(selected
[i
][j
]));
138 emul(vc
.get_bernoulli(s
, i
), f
);
155 static int first_non_zero(const vector
<int>& row
)
157 for (int i
= 0; i
< row
.size(); ++i
)
163 /* Return coefficient of the term with exponents powers by
164 * iterating over all combinations of exponents for each ray
165 * that sum up to the given exponents.
167 const evalue
*todd_product::get_coefficient(const vector
<int> &powers
)
171 HASH_MAP
<vector
<int>, const evalue
*>::iterator i
;
172 i
= cache
.find(powers
);
173 if (i
!= cache
.end())
176 for (int i
= 0; i
< vc
.dim
; ++i
)
177 for (int j
= 0; j
< vc
.dim
; ++j
)
181 int nz
= first_non_zero(left
);
182 int level
= last_level
[nz
];
185 if (mask
[level
][p
] && left
[p
] > 0) {
186 selected
[level
][p
]++;
188 /* Fill out remaining powers and make sure we backtrack from
189 * the right position.
191 for (int i
= 0; i
< vc
.dim
; ++i
) {
194 selected
[last_level
[i
]][i
] += left
[i
];
196 if (last_level
[i
] >= level
) {
197 level
= last_level
[i
];
204 if (selected
[level
][p
]) {
205 left
[p
] += selected
[level
][p
];
206 selected
[level
][p
] = 0;
217 /* Maintains the coefficients of the reciprocals of the
218 * (negated) rays of the vertex cone vc.
223 /* can_borrow_from[i][j] = 1 if there is a ray
224 * with first non-zero coefficient i and a subsequent
225 * non-zero coefficient j.
227 vector
< vector
<int> > can_borrow_from
;
228 /* Total exponent that a variable can borrow from subsequent vars */
229 vector
<int> can_borrow
;
230 /* has_borrowed_from[i][j] is the exponent borrowed by i from j */
231 vector
< vector
<int> > has_borrowed_from
;
232 /* Total exponent borrowed from subsequent vars */
233 vector
<int> has_borrowed
;
234 /* The last variable that can borrow from subsequent vars */
237 /* Position of the first non-zero coefficient in each ray. */
240 /* Power without any "borrowing" */
241 vector
<int> base_power
;
242 /* Power after "borrowing" */
245 /* The non-zero coefficients in the rays of the vertex cone,
248 vector
< vector
<int> > mask
;
249 /* For each ray, the (positive) power of each variable it contributes */
250 vector
< vector
<int> > selected
;
251 /* The powers of each variable that still need to be selected */
254 HASH_MAP
<vector
<int>, const evalue
*> cache
;
256 reciprocal(vertex_cone
&vc
);
257 void start(vector
<int> &power
);
260 evalue
*add(evalue
*sum
);
261 const evalue
*get_coefficient();
263 HASH_MAP
<vector
<int>, const evalue
*>::iterator j
;
264 for (j
= cache
.begin(); j
!= cache
.end(); ++j
)
266 evalue_free(const_cast<evalue
*>((*j
).second
));
270 reciprocal::reciprocal(vertex_cone
&vc
) : vc(vc
)
272 for (int i
= 0; i
< vc
.dim
; ++i
) {
273 can_borrow_from
.push_back(vector
<int>(vc
.dim
));
274 has_borrowed_from
.push_back(vector
<int>(vc
.dim
));
275 mask
.push_back(vector
<int>(vc
.dim
));
276 selected
.push_back(vector
<int>(vc
.dim
));
278 can_borrow
= vector
<int>(vc
.dim
);
279 has_borrowed
= vector
<int>(vc
.dim
);
280 neg
= vector
<int>(vc
.dim
);
281 left
= vector
<int>(vc
.dim
);
283 for (int i
= 0; i
< vc
.dim
; ++i
) {
284 int pos
= First_Non_Zero(vc
.coeff
[i
]->p
, vc
.coeff
[i
]->Size
);
286 for (int j
= pos
+1; j
< vc
.dim
; ++j
)
287 if (value_notzero_p(vc
.coeff
[i
]->p
[j
])) {
289 can_borrow_from
[neg
[i
]][j
] = 1;
294 /* Initialize power to the exponent of the todd product
295 * required to compute the coefficient in the full product
296 * of the term with exponent req_power, without any
299 void reciprocal::start(vector
<int> &req_power
)
302 for (int j
= 0; j
< vc
.dim
; ++j
)
308 for (int i
= 0; i
< vc
.dim
; ++i
) {
311 for (int j
= i
+1; j
< vc
.dim
; ++j
) {
312 has_borrowed_from
[i
][j
] = 0;
313 if (can_borrow_from
[i
][j
])
314 can_borrow
[i
] += power
[j
];
321 /* Set power to the next exponent of the todd product required
322 * and return 1 as long as there is any such exponent left.
324 int reciprocal::next()
328 if (has_borrowed
[p
] < can_borrow
[p
]) {
330 for (j
= p
+1; j
< vc
.dim
; ++j
)
331 if (can_borrow_from
[p
][j
]) {
334 else if (has_borrowed_from
[p
][j
]) {
335 power
[j
] += has_borrowed_from
[p
][j
];
336 power
[p
] -= has_borrowed_from
[p
][j
];
337 has_borrowed
[p
] -= has_borrowed_from
[p
][j
];
338 has_borrowed_from
[p
][j
] = 0;
342 has_borrowed_from
[p
][j
]++;
349 if (has_borrowed
[p
]) {
350 for (int j
= p
+1; j
< vc
.dim
; ++j
)
351 if (has_borrowed_from
[p
][j
]) {
352 power
[j
] += has_borrowed_from
[p
][j
];
353 has_borrowed_from
[p
][j
] = 0;
355 power
[p
] -= has_borrowed
[p
];
363 /* Add coefficient of selected powers of variables to sum
364 * and return the result.
365 * The contribution of each ray j of the vertex cone is
368 * ( k_{f+1}, \ldots, k_n ) (-1)^{K+1}
369 * c_f^{-K-1} c_{f+1}^{k_{f+1}} \cdots c_n^{k_n}
371 * K = \sum_{i=f+1}^n k_i
373 evalue
*reciprocal::add(evalue
*sum
)
376 for (int i
= 0; i
< vc
.dim
; ++i
) {
377 evalue
*c
= ALLOC(evalue
);
380 value_set_si(c
->d
, 1);
381 multinomial(selected
[i
], &c
->x
.n
);
383 for (int j
= 0; j
< vc
.dim
; ++j
) {
384 if (selected
[i
][j
] == 0)
386 value_multiply(c
->x
.n
, c
->x
.n
,
387 *(*vc
.coeff_power
[i
][j
])[selected
[i
][j
]]);
390 value_multiply(c
->d
, c
->d
, *(*vc
.coeff_power
[i
][neg
[i
]])[s
+1]);
392 value_oppose(c
->x
.n
, c
->x
.n
);
393 if (value_neg_p(c
->d
)) {
394 value_oppose(c
->d
, c
->d
);
395 value_oppose(c
->x
.n
, c
->x
.n
);
413 /* Return coefficient of the term with exponents powers by
414 * iterating over all combinations of exponents for each ray
415 * that sum up to the given exponents.
417 const evalue
*reciprocal::get_coefficient()
421 for (int j
= 0; j
< vc
.dim
; ++j
)
422 left
[j
] = base_power
[j
] - power
[j
];
424 HASH_MAP
<vector
<int>, const evalue
*>::iterator i
;
425 i
= cache
.find(left
);
426 if (i
!= cache
.end())
429 int nz
= first_non_zero(left
);
431 return cache
[power
] = add(c
);
435 for (int i
= 0; i
< vc
.dim
; ++i
)
436 for (int j
= 0; j
< vc
.dim
; ++j
)
439 int level
= vc
.dim
-1;
442 int nz
= first_non_zero(left
);
443 if (nz
< neg
[level
] || (nz
== neg
[level
] && left
[nz
] > 0)) {
444 assert(p
== vc
.dim
-1);
448 if (nz
== neg
[level
] && mask
[level
][p
]) {
449 selected
[level
][p
]++;
452 int nz
= first_non_zero(left
);
455 else if (left
[nz
] < 0) {
461 if (selected
[level
][p
]) {
462 left
[p
] += selected
[level
][p
];
463 left
[neg
[level
]] -= selected
[level
][p
];
464 selected
[level
][p
] = 0;
476 struct laurent_summator_old
: public signed_cone_consumer
,
477 public vertex_decomposer
{
478 const evalue
*polynomial
;
481 param_polynomial poly
;
485 laurent_summator_old(const evalue
*e
, unsigned dim
, Param_Polyhedron
*PP
) :
486 vertex_decomposer(PP
, *this), polynomial(e
), dim(dim
),
487 vc(dim
), poly(e
, dim
) {
488 max_power
= dim
+ poly
.degree();
491 ~laurent_summator_old() {
495 virtual void handle(const signed_cone
& sc
, barvinok_options
*options
);
498 void laurent_summator_old::handle(const signed_cone
& sc
, barvinok_options
*options
)
502 vc
.init(sc
.rays
, V
, max_power
);
503 reciprocal
recip(vc
);
505 for (int i
= 0; i
< poly
.terms
.size(); ++i
) {
506 recip
.start(poly
.terms
[i
].powers
);
508 const evalue
*c
= recip
.get_coefficient();
512 const evalue
*t
= tp
.get_coefficient(recip
.power
);
514 evalue
*f
= evalue_dup(poly
.terms
[i
].coeff
);
517 for (int j
= 0; j
< dim
; ++j
)
518 evalue_mul(f
, *factorial(poly
.terms
[i
].powers
[j
]));
519 evalue_shift_variables(f
, 0, -dim
);
528 } while (recip
.next());
533 evalue
*laurent_summate_old(Param_Polyhedron
*PP
, Polyhedron
*TC
,
534 evalue
*e
, unsigned nvar
, struct barvinok_options
*options
)
536 struct evalue_section
*s
;
541 for (nd
= 0, PD
= PP
->D
; PD
; ++nd
, PD
= PD
->next
);
542 s
= ALLOCN(struct evalue_section
, nd
);
544 FORALL_REDUCED_DOMAIN(PP
, TC
, nd
, options
, i
, PD
, rVD
)
546 laurent_summator_old
ls(e
, nvar
, PP
);
548 FORALL_PVertex_in_ParamPolyhedron(V
, PD
, PP
) // _i internal counter
549 ls
.decompose_at_vertex(V
, _i
, options
);
550 END_FORALL_PVertex_in_ParamPolyhedron
;
555 END_FORALL_REDUCED_DOMAIN
557 sum
= evalue_from_section_array(s
, nd
);