evalue.c: reduce_evalue: reduce floor with constant argument
[barvinok/uuh.git] / laurent.cc
blob314778c1052ea66392c3315f17769fa9a4c34a9d
1 #include <assert.h>
2 #include <iostream>
3 #include <vector>
4 #include <barvinok/options.h>
5 #include "bernoulli.h"
6 #include "binomial.h"
7 #include "conversion.h"
8 #include "decomposer.h"
9 #include "lattice_point.h"
10 #include "laurent.h"
11 #include "param_util.h"
12 #include "power.h"
13 #include "reduce_domain.h"
14 #include "config.h"
16 using std::cerr;
17 using std::ostream;
18 using std::endl;
19 using std::vector;
21 #ifdef HAVE_GNUCXX_HASHMAP
23 #include <ext/hash_map>
25 #define HASH_MAP __gnu_cxx::hash_map
27 namespace __gnu_cxx
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)
35 __h = 5 * __h + x[i];
36 return size_t(__h);
41 #else
43 #warning "no hash_map available"
44 #include <map>
45 #define HASH_MAP std::map
47 #endif
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)
54 os << "[";
55 for (int i = 0; i < v.size(); ++i) {
56 if (i)
57 os << ", ";
58 os << v[i];
60 os << "]";
61 return os;
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)
70 int pa, pb;
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);
77 if (pa == pb) {
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);
82 return pa - pb;
85 /* Represents the vertex and the rays of a vertex cone */
86 struct vertex_cone {
87 unsigned dim;
88 /* The coefficients of the rays, ordered according
89 * to the first non-zero coefficient.
91 Vector **coeff;
92 Matrix Rays;
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
99 * the vertex cone.
101 evalue **E_vertex;
102 unsigned max_power;
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);
108 void clear();
110 const evalue *get_bernoulli(int n, int i);
112 ~vertex_cone() {
113 for (int i = 0; i < dim; ++i)
114 Vector_Free(coeff[i]);
115 free(coeff);
116 delete [] E_vertex;
117 free(Rays.p);
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,
143 unsigned max_power)
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);
156 else
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);
165 Matrix_Free(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);
169 Matrix_Free(L);
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)
183 assert(n > 0);
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],
187 E_vertex[i]);
189 return bernoulli_t[i][n-1];
192 void vertex_cone::clear()
194 for (int i = 0; i < dim; ++i)
195 if (E_vertex[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 {
214 vertex_cone &vc;
215 unsigned dim;
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 */
221 vector<int> left;
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);
231 ~todd_product() {
232 HASH_MAP<const vector<int>, const evalue *>::iterator j;
233 for (j = cache.begin(); j != cache.end(); ++j)
234 if ((*j).second)
235 evalue_free(const_cast<evalue *>((*j).second));
239 todd_product::todd_product(vertex_cone &vc) : vc(vc)
241 dim = vc.dim;
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]) {
250 mask[i][j] = 1;
251 last_level[j] = i;
257 void multinomial(const vector<int> &k, Value *m)
259 int s = 0;
260 value_set_si(*m, 1);
261 for (int i = 0; i < k.size(); ++i) {
262 if (k[i] == 0)
263 continue;
264 s += k[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
273 * ( \sum k )
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)
281 evalue *c = NULL;
282 for (int i = 0; i < dim; ++i) {
283 int s = 0;
284 evalue *f = ALLOC(evalue);
285 value_init(f->d);
286 evalue_set_si(f, 1, 1);
287 for (int j = 0; j < dim; ++j) {
288 if (!selected[i][j])
289 continue;
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]));
293 s += selected[i][j];
295 if (s > 0)
296 emul(vc.get_bernoulli(s, i), f);
297 if (!c)
298 c = f;
299 else {
300 emul(f, c);
301 evalue_free(f);
304 if (!sum)
305 sum = c;
306 else {
307 eadd(c, sum);
308 evalue_free(c);
310 return sum;
313 static int first_non_zero(const vector<int>& row)
315 for (int i = 0; i < row.size(); ++i)
316 if (row[i] != 0)
317 return i;
318 return -1;
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)
327 evalue *c = NULL;
329 HASH_MAP<const vector<int>, const evalue *>::iterator i;
330 i = cache.find(powers);
331 if (i != cache.end())
332 return (*i).second;
334 for (int i = 0; i < vc.dim; ++i)
335 for (int j = 0; j < vc.dim; ++j)
336 selected[i][j] = 0;
338 left = powers;
339 int nz = first_non_zero(left);
340 int level = last_level[nz];
341 int p = nz;
342 while (level >= 0) {
343 if (mask[level][p] && left[p] > 0) {
344 selected[level][p]++;
345 left[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) {
350 if (left[i] == 0)
351 continue;
352 selected[last_level[i]][i] += left[i];
353 left[i] = 0;
354 if (last_level[i] >= level) {
355 level = last_level[i];
356 p = i;
360 c = add(c);
362 if (selected[level][p]) {
363 left[p] += selected[level][p];
364 selected[level][p] = 0;
366 if (--p < 0) {
367 --level;
368 p = dim-1;
371 cache[powers] = c;
372 return c;
375 /* Maintains the coefficients of the reciprocals of the
376 * (negated) rays of the vertex cone vc.
378 struct reciprocal {
379 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 */
393 int last;
395 /* Position of the first non-zero coefficient in each ray. */
396 vector<int> neg;
398 /* Power without any "borrowing" */
399 vector<int> base_power;
400 /* Power after "borrowing" */
401 vector<int> power;
403 /* The non-zero coefficients in the rays of the vertex cone,
404 * except the first.
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 */
410 vector<int> left;
412 HASH_MAP<const vector<int>, const evalue *> cache;
414 reciprocal(vertex_cone &vc);
415 void start(vector<int> &power);
416 int next();
418 evalue *add(evalue *sum);
419 const evalue *get_coefficient();
420 ~reciprocal() {
421 HASH_MAP<const vector<int>, const evalue *>::iterator j;
422 for (j = cache.begin(); j != cache.end(); ++j)
423 if ((*j).second)
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);
443 neg[i] = pos;
444 for (int j = pos+1; j < vc.dim; ++j)
445 if (value_notzero_p(vc.coeff[i]->p[j])) {
446 mask[i][j] = 1;
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
455 * "borrowing".
457 void reciprocal::start(vector<int> &req_power)
459 power = req_power;
460 for (int j = 0; j < vc.dim; ++j)
461 power[neg[j]]++;
463 base_power = power;
465 last = -1;
466 for (int i = 0; i < vc.dim; ++i) {
467 can_borrow[i] = 0;
468 has_borrowed[i] = 0;
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];
474 if (can_borrow[i])
475 last = i;
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()
484 int p = last;
485 while (p >= 0) {
486 if (has_borrowed[p] < can_borrow[p]) {
487 int j;
488 for (j = p+1; j < vc.dim; ++j)
489 if (can_borrow_from[p][j]) {
490 if (power[j] > 0)
491 break;
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;
499 if (j < vc.dim) {
500 has_borrowed_from[p][j]++;
501 has_borrowed[p]++;
502 power[p]++;
503 power[j]--;
504 return 1;
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];
514 has_borrowed[p] = 0;
516 --p;
518 return 0;
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
525 * ( K )
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)
533 evalue *t = NULL;
534 for (int i = 0; i < vc.dim; ++i) {
535 evalue *c = ALLOC(evalue);
536 value_init(c->d);
537 value_init(c->x.n);
538 value_set_si(c->d, 1);
539 multinomial(selected[i], &c->x.n);
540 int s = 0;
541 for (int j = 0; j < vc.dim; ++j) {
542 if (selected[i][j] == 0)
543 continue;
544 value_multiply(c->x.n, c->x.n,
545 *(*vc.coeff_power[i][j])[selected[i][j]]);
546 s += selected[i][j];
548 value_multiply(c->d, c->d, *(*vc.coeff_power[i][neg[i]])[s+1]);
549 if (!(s % 2))
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);
555 if (!t)
556 t = c;
557 else {
558 emul(c, t);
559 evalue_free(c);
562 if (!sum)
563 sum = t;
564 else {
565 eadd(t, sum);
566 evalue_free(t);
568 return sum;
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()
577 evalue *c = NULL;
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())
585 return (*i).second;
587 int nz = first_non_zero(left);
588 if (nz == -1)
589 return cache[power] = add(c);
590 if (left[nz] > 0)
591 return NULL;
593 for (int i = 0; i < vc.dim; ++i)
594 for (int j = 0; j < vc.dim; ++j)
595 selected[i][j] = 0;
597 int level = vc.dim-1;
598 int p = vc.dim-1;
599 while (level >= 0) {
600 int nz = first_non_zero(left);
601 if (nz < neg[level] || (nz == neg[level] && left[nz] > 0)) {
602 assert(p == vc.dim-1);
603 --level;
604 continue;
606 if (nz == neg[level] && mask[level][p]) {
607 selected[level][p]++;
608 left[p]--;
609 left[neg[level]]++;
610 int nz = first_non_zero(left);
611 if (nz == -1)
612 c = add(c);
613 if (left[nz] < 0) {
614 level = vc.dim-1;
615 p = vc.dim-1;
616 continue;
619 if (selected[level][p]) {
620 left[p] += selected[level][p];
621 left[neg[level]] -= selected[level][p];
622 selected[level][p] = 0;
624 if (--p < 0) {
625 --level;
626 p = vc.dim-1;
629 cache[left] = c;
631 return c;
634 /* A term in the input polynomial */
635 struct term {
636 vector<int> powers;
637 const evalue *coeff;
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))
644 return;
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) {
649 struct term t;
650 t.powers = powers;
651 t.coeff = polynomial;
652 terms.push_back(t);
653 return;
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)
670 powers[i] = 0;
671 collect_terms_r(terms, powers, polynomial, nvar);
673 unsigned max_degree = 0;
674 for (int i = 0; i < terms.size(); ++i) {
675 int sum = 0;
676 for (int j = 0; j < nvar; ++j)
677 sum += terms[i].powers[j];
678 if (sum > max_degree)
679 max_degree = sum;
681 return 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;
697 unsigned dim;
698 vertex_cone vc;
699 vector<struct term> terms;
700 evalue *result;
701 unsigned max_power;
703 laurent_summator(const evalue *e, unsigned dim, Param_Polyhedron *PP) :
704 polynomial(e), dim(dim), vertex_decomposer(PP, *this),
705 vc(dim) {
706 max_power = dim + collect_terms(terms, polynomial, dim);
707 result = NULL;
709 ~laurent_summator() {
710 if (result)
711 evalue_free(result);
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)
719 if (row[i] != 0)
720 return i;
721 return -1;
724 void laurent_summator::handle(const signed_cone& sc, barvinok_options *options)
726 assert(sc.det == 1);
728 vc.init(sc.rays, V, max_power);
729 reciprocal recip(vc);
730 todd_product tp(vc);
731 for (int i = 0; i < terms.size(); ++i) {
732 recip.start(terms[i].powers);
733 do {
734 const evalue *c = recip.get_coefficient();
735 if (!c)
736 continue;
738 const evalue *t = tp.get_coefficient(recip.power);
740 evalue *f = evalue_dup(terms[i].coeff);
741 if (sc.sign < 0)
742 evalue_negate(f);
743 for (int j = 0; j < dim; ++j)
744 evalue_mul(f, *factorial(terms[i].powers[j]));
745 evalue_shift_variables(f, -dim);
746 emul(c, f);
747 emul(t, f);
748 if (!result)
749 result = f;
750 else {
751 eadd(f, result);
752 evalue_free(f);
754 } while (recip.next());
756 vc.clear();
759 static evalue *summate_over_domain(const evalue *e, unsigned nvar,
760 Polyhedron *D,
761 struct barvinok_options *options)
763 Polyhedron *U, *TC;
764 Param_Polyhedron *PP;
765 struct evalue_section *s;
766 int nd = -1;
767 Param_Domain *PD;
768 evalue *sum;
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)
778 Param_Vertices *V;
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;
785 s[i].D = rVD;
786 s[i].E = ls.result;
787 ls.result = NULL;
788 END_FORALL_REDUCED_DOMAIN
789 Polyhedron_Free(TC);
790 Polyhedron_Free(U);
791 Param_Polyhedron_Free(PP);
793 sum = evalue_from_section_array(s, nd);
794 free(s);
796 return sum;
799 evalue *laurent_summate(evalue *e, unsigned nvar,
800 struct barvinok_options *options)
802 int i;
803 evalue *res;
805 assert(nvar >= 0);
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);
812 res = evalue_zero();
814 for (i = 0; i < e->x.p->size/2; ++i) {
815 evalue *t;
816 t = summate_over_domain(&e->x.p->arr[2*i+1], nvar,
817 EVALUE_DOMAIN(e->x.p->arr[2*i]), options);
818 eadd(t, res);
819 evalue_free(t);
822 return res;