isl_union_set_apply_union_pw_qpolynomial: rename "dim" variable to "space"
[barvinok.git] / laurent_old.cc
blob06629e2828d8cf3f2d07f1edff9e0c4a4db62fb7
1 #include <assert.h>
2 #include <iostream>
3 #include <vector>
4 #include <barvinok/options.h>
5 #include "binomial.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"
13 #include "config.h"
15 using std::cerr;
16 using std::ostream;
17 using std::endl;
18 using std::vector;
20 #if defined HAVE_UNORDERED_MAP
22 #include <unordered_map>
24 #define HASH_MAP std::unordered_map
26 namespace std
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)
34 __h = 5 * __h + x[i];
35 return size_t(__h);
40 #elif defined HAVE_GNUCXX_HASHMAP
42 #include <ext/hash_map>
44 #define HASH_MAP __gnu_cxx::hash_map
46 namespace __gnu_cxx
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)
54 __h = 5 * __h + x[i];
55 return size_t(__h);
60 #else
62 #warning "no hash_map available"
63 #include <map>
64 #define HASH_MAP std::map
66 #endif
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)
75 os << "[";
76 for (int i = 0; i < v.size(); ++i) {
77 if (i)
78 os << ", ";
79 os << v[i];
81 os << "]";
82 return os;
85 struct todd_product {
86 vertex_cone &vc;
87 unsigned dim;
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 */
93 vector<int> left;
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);
103 ~todd_product() {
104 HASH_MAP<vector<int>, const evalue *>::iterator j;
105 for (j = cache.begin(); j != cache.end(); ++j)
106 if ((*j).second)
107 evalue_free(const_cast<evalue *>((*j).second));
111 todd_product::todd_product(vertex_cone &vc) : vc(vc)
113 dim = vc.dim;
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]) {
122 mask[i][j] = 1;
123 last_level[j] = i;
129 void multinomial(const vector<int> &k, Value *m)
131 int s = 0;
132 value_set_si(*m, 1);
133 for (int i = 0; i < k.size(); ++i) {
134 if (k[i] == 0)
135 continue;
136 s += k[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
145 * ( \sum k )
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)
153 evalue *c = NULL;
154 for (int i = 0; i < dim; ++i) {
155 int s = 0;
156 evalue *f = ALLOC(evalue);
157 value_init(f->d);
158 evalue_set_si(f, 1, 1);
159 for (int j = 0; j < dim; ++j) {
160 if (!selected[i][j])
161 continue;
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]));
165 s += selected[i][j];
167 if (s > 0)
168 emul(vc.get_bernoulli(s, i), f);
169 if (!c)
170 c = f;
171 else {
172 emul(f, c);
173 evalue_free(f);
176 if (!sum)
177 sum = c;
178 else {
179 eadd(c, sum);
180 evalue_free(c);
182 return sum;
185 static int first_non_zero(const vector<int>& row)
187 for (int i = 0; i < row.size(); ++i)
188 if (row[i] != 0)
189 return i;
190 return -1;
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)
199 evalue *c = NULL;
201 HASH_MAP<vector<int>, const evalue *>::iterator i;
202 i = cache.find(powers);
203 if (i != cache.end())
204 return (*i).second;
206 for (int i = 0; i < vc.dim; ++i)
207 for (int j = 0; j < vc.dim; ++j)
208 selected[i][j] = 0;
210 left = powers;
211 int nz = first_non_zero(left);
212 int level = last_level[nz];
213 int p = nz;
214 while (level >= 0) {
215 if (mask[level][p] && left[p] > 0) {
216 selected[level][p]++;
217 left[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) {
222 if (left[i] == 0)
223 continue;
224 selected[last_level[i]][i] += left[i];
225 left[i] = 0;
226 if (last_level[i] >= level) {
227 level = last_level[i];
228 p = i;
232 c = add(c);
234 if (selected[level][p]) {
235 left[p] += selected[level][p];
236 selected[level][p] = 0;
238 if (--p < 0) {
239 --level;
240 p = dim-1;
243 cache[powers] = c;
244 return c;
247 /* Maintains the coefficients of the reciprocals of the
248 * (negated) rays of the vertex cone vc.
250 struct reciprocal {
251 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 */
265 int last;
267 /* Position of the first non-zero coefficient in each ray. */
268 vector<int> neg;
270 /* Power without any "borrowing" */
271 vector<int> base_power;
272 /* Power after "borrowing" */
273 vector<int> power;
275 /* The non-zero coefficients in the rays of the vertex cone,
276 * except the first.
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 */
282 vector<int> left;
284 HASH_MAP<vector<int>, const evalue *> cache;
286 reciprocal(vertex_cone &vc);
287 void start(vector<int> &power);
288 int next();
290 evalue *add(evalue *sum);
291 const evalue *get_coefficient();
292 ~reciprocal() {
293 HASH_MAP<vector<int>, const evalue *>::iterator j;
294 for (j = cache.begin(); j != cache.end(); ++j)
295 if ((*j).second)
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);
315 neg[i] = pos;
316 for (int j = pos+1; j < vc.dim; ++j)
317 if (value_notzero_p(vc.coeff[i]->p[j])) {
318 mask[i][j] = 1;
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
327 * "borrowing".
329 void reciprocal::start(vector<int> &req_power)
331 power = req_power;
332 for (int j = 0; j < vc.dim; ++j)
333 power[neg[j]]++;
335 base_power = power;
337 last = -1;
338 for (int i = 0; i < vc.dim; ++i) {
339 can_borrow[i] = 0;
340 has_borrowed[i] = 0;
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];
346 if (can_borrow[i])
347 last = i;
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()
356 int p = last;
357 while (p >= 0) {
358 if (has_borrowed[p] < can_borrow[p]) {
359 int j;
360 for (j = p+1; j < vc.dim; ++j)
361 if (can_borrow_from[p][j]) {
362 if (power[j] > 0)
363 break;
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;
371 if (j < vc.dim) {
372 has_borrowed_from[p][j]++;
373 has_borrowed[p]++;
374 power[p]++;
375 power[j]--;
376 return 1;
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];
386 has_borrowed[p] = 0;
388 --p;
390 return 0;
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
397 * ( K )
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)
405 evalue *t = NULL;
406 for (int i = 0; i < vc.dim; ++i) {
407 evalue *c = ALLOC(evalue);
408 value_init(c->d);
409 value_init(c->x.n);
410 value_set_si(c->d, 1);
411 multinomial(selected[i], &c->x.n);
412 int s = 0;
413 for (int j = 0; j < vc.dim; ++j) {
414 if (selected[i][j] == 0)
415 continue;
416 value_multiply(c->x.n, c->x.n,
417 *(*vc.coeff_power[i][j])[selected[i][j]]);
418 s += selected[i][j];
420 value_multiply(c->d, c->d, *(*vc.coeff_power[i][neg[i]])[s+1]);
421 if (!(s % 2))
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);
427 if (!t)
428 t = c;
429 else {
430 emul(c, t);
431 evalue_free(c);
434 if (!sum)
435 sum = t;
436 else {
437 eadd(t, sum);
438 evalue_free(t);
440 return sum;
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()
449 evalue *c = NULL;
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())
457 return (*i).second;
459 int nz = first_non_zero(left);
460 if (nz == -1)
461 return cache[power] = add(c);
462 if (left[nz] > 0)
463 return NULL;
465 for (int i = 0; i < vc.dim; ++i)
466 for (int j = 0; j < vc.dim; ++j)
467 selected[i][j] = 0;
469 int level = vc.dim-1;
470 int p = vc.dim-1;
471 while (level >= 0) {
472 int nz = first_non_zero(left);
473 if (nz < neg[level] || (nz == neg[level] && left[nz] > 0)) {
474 assert(p == vc.dim-1);
475 --level;
476 continue;
478 if (nz == neg[level] && mask[level][p]) {
479 selected[level][p]++;
480 left[p]--;
481 left[neg[level]]++;
482 int nz = first_non_zero(left);
483 if (nz == -1)
484 c = add(c);
485 else if (left[nz] < 0) {
486 level = vc.dim-1;
487 p = vc.dim-1;
488 continue;
491 if (selected[level][p]) {
492 left[p] += selected[level][p];
493 left[neg[level]] -= selected[level][p];
494 selected[level][p] = 0;
496 if (--p < 0) {
497 --level;
498 p = vc.dim-1;
501 cache[left] = c;
503 return c;
506 struct laurent_summator_old : public signed_cone_consumer,
507 public vertex_decomposer {
508 const evalue *polynomial;
509 unsigned dim;
510 vertex_cone vc;
511 param_polynomial poly;
512 evalue *result;
513 unsigned max_power;
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();
519 result = NULL;
521 ~laurent_summator_old() {
522 if (result)
523 evalue_free(result);
525 virtual void handle(const signed_cone& sc, barvinok_options *options);
528 void laurent_summator_old::handle(const signed_cone& sc, barvinok_options *options)
530 assert(sc.det == 1);
532 vc.init(sc.rays, V, max_power);
533 reciprocal recip(vc);
534 todd_product tp(vc);
535 for (int i = 0; i < poly.terms.size(); ++i) {
536 recip.start(poly.terms[i].powers);
537 do {
538 const evalue *c = recip.get_coefficient();
539 if (!c)
540 continue;
542 const evalue *t = tp.get_coefficient(recip.power);
544 evalue *f = evalue_dup(poly.terms[i].coeff);
545 if (sc.sign < 0)
546 evalue_negate(f);
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);
550 emul(c, f);
551 emul(t, f);
552 if (!result)
553 result = f;
554 else {
555 eadd(f, result);
556 evalue_free(f);
558 } while (recip.next());
560 vc.clear();
563 evalue *laurent_summate_old(Polyhedron *P, evalue *e, unsigned nvar,
564 struct barvinok_options *options)
566 Polyhedron *U, *TC;
567 Param_Polyhedron *PP;
568 struct evalue_section *s;
569 int nd = -1;
570 Param_Domain *PD;
571 evalue *sum;
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)
581 Param_Vertices *V;
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;
588 s[i].D = rVD;
589 s[i].E = ls.result;
590 ls.result = NULL;
591 END_FORALL_REDUCED_DOMAIN
592 Polyhedron_Free(TC);
593 Polyhedron_Free(U);
594 Param_Polyhedron_Free(PP);
596 sum = evalue_from_section_array(s, nd);
597 free(s);
599 return sum;