use test scripts for performing tests
[barvinok.git] / laurent_old.cc
blobeb15278f76ce07a4b30ecf8aa7abef9fa9add86d
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 #include <unordered_map>
22 #define HASH_MAP std::unordered_map
24 namespace std
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)
32 __h = 5 * __h + x[i];
33 return size_t(__h);
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)
45 os << "[";
46 for (int i = 0; i < v.size(); ++i) {
47 if (i)
48 os << ", ";
49 os << v[i];
51 os << "]";
52 return os;
55 struct todd_product {
56 vertex_cone &vc;
57 unsigned dim;
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 */
63 vector<int> left;
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);
73 ~todd_product() {
74 HASH_MAP<vector<int>, const evalue *>::iterator j;
75 for (j = cache.begin(); j != cache.end(); ++j)
76 if ((*j).second)
77 evalue_free(const_cast<evalue *>((*j).second));
81 todd_product::todd_product(vertex_cone &vc) : vc(vc)
83 dim = vc.dim;
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]) {
92 mask[i][j] = 1;
93 last_level[j] = i;
99 void multinomial(const vector<int> &k, Value *m)
101 int s = 0;
102 value_set_si(*m, 1);
103 for (int i = 0; i < k.size(); ++i) {
104 if (k[i] == 0)
105 continue;
106 s += k[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
115 * ( \sum k )
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)
123 evalue *c = NULL;
124 for (int i = 0; i < dim; ++i) {
125 int s = 0;
126 evalue *f = ALLOC(evalue);
127 value_init(f->d);
128 evalue_set_si(f, 1, 1);
129 for (int j = 0; j < dim; ++j) {
130 if (!selected[i][j])
131 continue;
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]));
135 s += selected[i][j];
137 if (s > 0)
138 emul(vc.get_bernoulli(s, i), f);
139 if (!c)
140 c = f;
141 else {
142 emul(f, c);
143 evalue_free(f);
146 if (!sum)
147 sum = c;
148 else {
149 eadd(c, sum);
150 evalue_free(c);
152 return sum;
155 static int first_non_zero(const vector<int>& row)
157 for (int i = 0; i < row.size(); ++i)
158 if (row[i] != 0)
159 return i;
160 return -1;
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)
169 evalue *c = NULL;
171 HASH_MAP<vector<int>, const evalue *>::iterator i;
172 i = cache.find(powers);
173 if (i != cache.end())
174 return (*i).second;
176 for (int i = 0; i < vc.dim; ++i)
177 for (int j = 0; j < vc.dim; ++j)
178 selected[i][j] = 0;
180 left = powers;
181 int nz = first_non_zero(left);
182 int level = last_level[nz];
183 int p = nz;
184 while (level >= 0) {
185 if (mask[level][p] && left[p] > 0) {
186 selected[level][p]++;
187 left[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) {
192 if (left[i] == 0)
193 continue;
194 selected[last_level[i]][i] += left[i];
195 left[i] = 0;
196 if (last_level[i] >= level) {
197 level = last_level[i];
198 p = i;
202 c = add(c);
204 if (selected[level][p]) {
205 left[p] += selected[level][p];
206 selected[level][p] = 0;
208 if (--p < 0) {
209 --level;
210 p = dim-1;
213 cache[powers] = c;
214 return c;
217 /* Maintains the coefficients of the reciprocals of the
218 * (negated) rays of the vertex cone vc.
220 struct reciprocal {
221 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 */
235 int last;
237 /* Position of the first non-zero coefficient in each ray. */
238 vector<int> neg;
240 /* Power without any "borrowing" */
241 vector<int> base_power;
242 /* Power after "borrowing" */
243 vector<int> power;
245 /* The non-zero coefficients in the rays of the vertex cone,
246 * except the first.
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 */
252 vector<int> left;
254 HASH_MAP<vector<int>, const evalue *> cache;
256 reciprocal(vertex_cone &vc);
257 void start(vector<int> &power);
258 int next();
260 evalue *add(evalue *sum);
261 const evalue *get_coefficient();
262 ~reciprocal() {
263 HASH_MAP<vector<int>, const evalue *>::iterator j;
264 for (j = cache.begin(); j != cache.end(); ++j)
265 if ((*j).second)
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);
285 neg[i] = pos;
286 for (int j = pos+1; j < vc.dim; ++j)
287 if (value_notzero_p(vc.coeff[i]->p[j])) {
288 mask[i][j] = 1;
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
297 * "borrowing".
299 void reciprocal::start(vector<int> &req_power)
301 power = req_power;
302 for (int j = 0; j < vc.dim; ++j)
303 power[neg[j]]++;
305 base_power = power;
307 last = -1;
308 for (int i = 0; i < vc.dim; ++i) {
309 can_borrow[i] = 0;
310 has_borrowed[i] = 0;
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];
316 if (can_borrow[i])
317 last = i;
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()
326 int p = last;
327 while (p >= 0) {
328 if (has_borrowed[p] < can_borrow[p]) {
329 int j;
330 for (j = p+1; j < vc.dim; ++j)
331 if (can_borrow_from[p][j]) {
332 if (power[j] > 0)
333 break;
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;
341 if (j < vc.dim) {
342 has_borrowed_from[p][j]++;
343 has_borrowed[p]++;
344 power[p]++;
345 power[j]--;
346 return 1;
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];
356 has_borrowed[p] = 0;
358 --p;
360 return 0;
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
367 * ( K )
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)
375 evalue *t = NULL;
376 for (int i = 0; i < vc.dim; ++i) {
377 evalue *c = ALLOC(evalue);
378 value_init(c->d);
379 value_init(c->x.n);
380 value_set_si(c->d, 1);
381 multinomial(selected[i], &c->x.n);
382 int s = 0;
383 for (int j = 0; j < vc.dim; ++j) {
384 if (selected[i][j] == 0)
385 continue;
386 value_multiply(c->x.n, c->x.n,
387 *(*vc.coeff_power[i][j])[selected[i][j]]);
388 s += selected[i][j];
390 value_multiply(c->d, c->d, *(*vc.coeff_power[i][neg[i]])[s+1]);
391 if (!(s % 2))
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);
397 if (!t)
398 t = c;
399 else {
400 emul(c, t);
401 evalue_free(c);
404 if (!sum)
405 sum = t;
406 else {
407 eadd(t, sum);
408 evalue_free(t);
410 return sum;
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()
419 evalue *c = NULL;
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())
427 return (*i).second;
429 int nz = first_non_zero(left);
430 if (nz == -1)
431 return cache[power] = add(c);
432 if (left[nz] > 0)
433 return NULL;
435 for (int i = 0; i < vc.dim; ++i)
436 for (int j = 0; j < vc.dim; ++j)
437 selected[i][j] = 0;
439 int level = vc.dim-1;
440 int p = vc.dim-1;
441 while (level >= 0) {
442 int nz = first_non_zero(left);
443 if (nz < neg[level] || (nz == neg[level] && left[nz] > 0)) {
444 assert(p == vc.dim-1);
445 --level;
446 continue;
448 if (nz == neg[level] && mask[level][p]) {
449 selected[level][p]++;
450 left[p]--;
451 left[neg[level]]++;
452 int nz = first_non_zero(left);
453 if (nz == -1)
454 c = add(c);
455 else if (left[nz] < 0) {
456 level = vc.dim-1;
457 p = vc.dim-1;
458 continue;
461 if (selected[level][p]) {
462 left[p] += selected[level][p];
463 left[neg[level]] -= selected[level][p];
464 selected[level][p] = 0;
466 if (--p < 0) {
467 --level;
468 p = vc.dim-1;
471 cache[left] = c;
473 return c;
476 struct laurent_summator_old : public signed_cone_consumer,
477 public vertex_decomposer {
478 const evalue *polynomial;
479 unsigned dim;
480 vertex_cone vc;
481 param_polynomial poly;
482 evalue *result;
483 unsigned max_power;
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();
489 result = NULL;
491 ~laurent_summator_old() {
492 if (result)
493 evalue_free(result);
495 virtual void handle(const signed_cone& sc, barvinok_options *options);
498 void laurent_summator_old::handle(const signed_cone& sc, barvinok_options *options)
500 assert(sc.det == 1);
502 vc.init(sc.rays, V, max_power);
503 reciprocal recip(vc);
504 todd_product tp(vc);
505 for (int i = 0; i < poly.terms.size(); ++i) {
506 recip.start(poly.terms[i].powers);
507 do {
508 const evalue *c = recip.get_coefficient();
509 if (!c)
510 continue;
512 const evalue *t = tp.get_coefficient(recip.power);
514 evalue *f = evalue_dup(poly.terms[i].coeff);
515 if (sc.sign < 0)
516 evalue_negate(f);
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);
520 emul(c, f);
521 emul(t, f);
522 if (!result)
523 result = f;
524 else {
525 eadd(f, result);
526 evalue_free(f);
528 } while (recip.next());
530 vc.clear();
533 evalue *laurent_summate_old(Polyhedron *P, evalue *e, unsigned nvar,
534 struct barvinok_options *options)
536 Polyhedron *U, *TC;
537 Param_Polyhedron *PP;
538 struct evalue_section *s;
539 int nd = -1;
540 Param_Domain *PD;
541 evalue *sum;
543 U = Universe_Polyhedron(P->Dimension - nvar);
544 PP = Polyhedron2Param_Polyhedron(P, U, options);
546 for (nd = 0, PD = PP->D; PD; ++nd, PD = PD->next);
547 s = ALLOCN(struct evalue_section, nd);
549 TC = true_context(P, U, options->MaxRays);
550 FORALL_REDUCED_DOMAIN(PP, TC, nd, options, i, PD, rVD)
551 Param_Vertices *V;
552 laurent_summator_old ls(e, nvar, PP);
554 FORALL_PVertex_in_ParamPolyhedron(V, PD, PP) // _i internal counter
555 ls.decompose_at_vertex(V, _i, options);
556 END_FORALL_PVertex_in_ParamPolyhedron;
558 s[i].D = rVD;
559 s[i].E = ls.result;
560 ls.result = NULL;
561 END_FORALL_REDUCED_DOMAIN
562 Polyhedron_Free(TC);
563 Polyhedron_Free(U);
564 Param_Polyhedron_Free(PP);
566 sum = evalue_from_section_array(s, nd);
567 free(s);
569 return sum;