remove equalities from parametrized domains
[barvinok.git] / barvinok.cc
blobbf36f40a253eee813706cd0e37bb8e35e885c010
1 #include <assert.h>
2 #include <iostream>
3 #include <vector>
4 #include <deque>
5 #include <string>
6 #include <sstream>
7 #include <gmp.h>
8 #include <NTL/mat_ZZ.h>
9 #include <NTL/LLL.h>
10 #include "ehrhartpolynom.h"
11 #include <barvinok.h>
12 #include <util.h>
13 extern "C" {
14 #include <polylib/polylibgmp.h>
17 #ifdef NTL_STD_CXX
18 using namespace NTL;
19 #endif
20 using std::cout;
21 using std::endl;
22 using std::vector;
23 using std::deque;
24 using std::string;
25 using std::ostringstream;
27 #define ALLOC(p) (((long *) (p))[0])
28 #define SIZE(p) (((long *) (p))[1])
29 #define DATA(p) ((mp_limb_t *) (((long *) (p)) + 2))
31 static void value2zz(Value v, ZZ& z)
33 int sa = v[0]._mp_size;
34 int abs_sa = sa < 0 ? -sa : sa;
36 _ntl_gsetlength(&z.rep, abs_sa);
37 mp_limb_t * adata = DATA(z.rep);
38 for (int i = 0; i < abs_sa; ++i)
39 adata[i] = v[0]._mp_d[i];
40 SIZE(z.rep) = sa;
43 static void zz2value(ZZ& z, Value& v)
45 if (!z.rep) {
46 value_set_si(v, 0);
47 return;
50 int sa = SIZE(z.rep);
51 int abs_sa = sa < 0 ? -sa : sa;
53 mp_limb_t * adata = DATA(z.rep);
54 mpz_realloc2(v, __GMP_BITS_PER_MP_LIMB * abs_sa);
55 for (int i = 0; i < abs_sa; ++i)
56 v[0]._mp_d[i] = adata[i];
57 v[0]._mp_size = sa;
61 * We just ignore the last column and row
62 * If the final element is not equal to one
63 * then the result will actually be a multiple of the input
65 static void matrix2zz(Matrix *M, mat_ZZ& m, unsigned nr, unsigned nc)
67 m.SetDims(nr, nc);
69 for (int i = 0; i < nr; ++i) {
70 // assert(value_one_p(M->p[i][M->NbColumns - 1]));
71 for (int j = 0; j < nc; ++j) {
72 value2zz(M->p[i][j], m[i][j]);
77 static void values2zz(Value *p, vec_ZZ& v, int len)
79 v.SetLength(len);
81 for (int i = 0; i < len; ++i) {
82 value2zz(p[i], v[i]);
87 * We add a 0 at the end, because we need it afterwards
89 static Vector * zz2vector(vec_ZZ& v)
91 Vector *vec = Vector_Alloc(v.length()+1);
92 assert(vec);
93 for (int i = 0; i < v.length(); ++i)
94 zz2value(v[i], vec->p[i]);
96 value_set_si(vec->p[v.length()], 0);
98 return vec;
101 static void rays(mat_ZZ& r, Polyhedron *C)
103 unsigned dim = C->NbRays - 1; /* don't count zero vertex */
104 assert(C->NbRays - 1 == C->Dimension);
105 r.SetDims(dim, dim);
106 ZZ tmp;
108 int i, c;
109 for (i = 0, c = 0; i < dim; ++i)
110 if (value_zero_p(C->Ray[i][dim+1])) {
111 for (int j = 0; j < dim; ++j) {
112 value2zz(C->Ray[i][j+1], tmp);
113 r[j][c] = tmp;
115 ++c;
119 static Matrix * rays(Polyhedron *C)
121 unsigned dim = C->NbRays - 1; /* don't count zero vertex */
122 assert(C->NbRays - 1 == C->Dimension);
124 Matrix *M = Matrix_Alloc(dim+1, dim+1);
125 assert(M);
127 int i, c;
128 for (i = 0, c = 0; i <= dim && c < dim; ++i)
129 if (value_zero_p(C->Ray[i][dim+1])) {
130 Vector_Copy(C->Ray[i] + 1, M->p[c], dim);
131 value_set_si(M->p[c++][dim], 0);
133 assert(c == dim);
134 value_set_si(M->p[dim][dim], 1);
136 return M;
140 * Returns the largest absolute value in the vector
142 static ZZ max(vec_ZZ& v)
144 ZZ max = abs(v[0]);
145 for (int i = 1; i < v.length(); ++i)
146 if (abs(v[i]) > max)
147 max = abs(v[i]);
148 return max;
151 class cone {
152 public:
153 cone(Matrix *M) {
154 Cone = 0;
155 Rays = Matrix_Copy(M);
156 set_det();
158 cone(Polyhedron *C) {
159 Cone = Polyhedron_Copy(C);
160 Rays = rays(C);
161 set_det();
163 void set_det() {
164 mat_ZZ A;
165 matrix2zz(Rays, A, Rays->NbRows - 1, Rays->NbColumns - 1);
166 det = determinant(A);
167 Value v;
168 value_init(v);
169 zz2value(det, v);
170 value_clear(v);
173 Vector* short_vector(vec_ZZ& lambda) {
174 Matrix *M = Matrix_Copy(Rays);
175 Matrix *inv = Matrix_Alloc(M->NbRows, M->NbColumns);
176 int ok = Matrix_Inverse(M, inv);
177 assert(ok);
178 Matrix_Free(M);
180 ZZ det2;
181 mat_ZZ B;
182 mat_ZZ U;
183 matrix2zz(inv, B, inv->NbRows - 1, inv->NbColumns - 1);
184 long r = LLL(det2, B, U);
186 ZZ min = max(B[0]);
187 int index = 0;
188 for (int i = 1; i < B.NumRows(); ++i) {
189 ZZ tmp = max(B[i]);
190 if (tmp < min) {
191 min = tmp;
192 index = i;
196 Matrix_Free(inv);
198 lambda = B[index];
200 Vector *z = zz2vector(U[index]);
201 Value tmp;
202 value_init(tmp);
203 Polyhedron *C = poly();
204 int i;
205 for (i = 0; i < C->NbConstraints; ++i) {
206 Inner_Product(z->p, C->Constraint[i]+1, z->Size-1, &tmp);
207 if (value_pos_p(tmp))
208 break;
210 if (i == C->NbConstraints) {
211 value_set_si(tmp, -1);
212 Vector_Scale(z->p, z->p, tmp, z->Size-1);
214 value_clear(tmp);
215 return z;
218 ~cone() {
219 Polyhedron_Free(Cone);
220 Matrix_Free(Rays);
223 Polyhedron *poly() {
224 if (!Cone) {
225 Matrix *M = Matrix_Alloc(Rays->NbRows+1, Rays->NbColumns+1);
226 for (int i = 0; i < Rays->NbRows; ++i) {
227 Vector_Copy(Rays->p[i], M->p[i]+1, Rays->NbColumns);
228 value_set_si(M->p[i][0], 1);
230 Vector_Set(M->p[Rays->NbRows]+1, 0, Rays->NbColumns-1);
231 value_set_si(M->p[Rays->NbRows][0], 1);
232 value_set_si(M->p[Rays->NbRows][Rays->NbColumns], 1);
233 Cone = Rays2Polyhedron(M, M->NbRows+1);
234 assert(Cone->NbConstraints == Cone->NbRays);
235 Matrix_Free(M);
237 return Cone;
240 ZZ det;
241 Polyhedron *Cone;
242 Matrix *Rays;
245 class dpoly {
246 public:
247 vec_ZZ coeff;
248 dpoly(int d, ZZ& degree, int offset = 0) {
249 coeff.SetLength(d+1);
251 int min = d + offset;
252 if (degree < ZZ(INIT_VAL, min))
253 min = to_int(degree);
255 ZZ c = ZZ(INIT_VAL, 1);
256 if (!offset)
257 coeff[0] = c;
258 for (int i = 1; i <= min; ++i) {
259 c *= (degree -i + 1);
260 c /= i;
261 coeff[i-offset] = c;
264 void operator *= (dpoly& f) {
265 assert(coeff.length() == f.coeff.length());
266 vec_ZZ old = coeff;
267 coeff = f.coeff[0] * coeff;
268 for (int i = 1; i < coeff.length(); ++i)
269 for (int j = 0; i+j < coeff.length(); ++j)
270 coeff[i+j] += f.coeff[i] * old[j];
272 void div(dpoly& d, mpq_t count, ZZ& sign) {
273 int len = coeff.length();
274 Value tmp;
275 value_init(tmp);
276 mpq_t* c = new mpq_t[coeff.length()];
277 mpq_t qtmp;
278 mpq_init(qtmp);
279 for (int i = 0; i < len; ++i) {
280 mpq_init(c[i]);
281 zz2value(coeff[i], tmp);
282 mpq_set_z(c[i], tmp);
284 for (int j = 1; j <= i; ++j) {
285 zz2value(d.coeff[j], tmp);
286 mpq_set_z(qtmp, tmp);
287 mpq_mul(qtmp, qtmp, c[i-j]);
288 mpq_sub(c[i], c[i], qtmp);
291 zz2value(d.coeff[0], tmp);
292 mpq_set_z(qtmp, tmp);
293 mpq_div(c[i], c[i], qtmp);
295 if (sign == -1)
296 mpq_sub(count, count, c[len-1]);
297 else
298 mpq_add(count, count, c[len-1]);
300 value_clear(tmp);
301 mpq_clear(qtmp);
302 for (int i = 0; i < len; ++i)
303 mpq_clear(c[i]);
304 delete [] c;
308 class dpoly_n {
309 public:
310 Matrix *coeff;
311 ~dpoly_n() {
312 Matrix_Free(coeff);
314 dpoly_n(int d, ZZ& degree_0, ZZ& degree_1, int offset = 0) {
315 Value d0, d1;
316 value_init(d0);
317 value_init(d1);
318 zz2value(degree_0, d0);
319 zz2value(degree_1, d1);
320 coeff = Matrix_Alloc(d+1, d+1+1);
321 value_set_si(coeff->p[0][0], 1);
322 value_set_si(coeff->p[0][d+1], 1);
323 for (int i = 1; i <= d; ++i) {
324 value_multiply(coeff->p[i][0], coeff->p[i-1][0], d0);
325 Vector_Combine(coeff->p[i-1], coeff->p[i-1]+1, coeff->p[i]+1,
326 d1, d0, i);
327 value_set_si(coeff->p[i][d+1], i);
328 value_multiply(coeff->p[i][d+1], coeff->p[i][d+1], coeff->p[i-1][d+1]);
329 value_decrement(d0, d0);
331 value_clear(d0);
332 value_clear(d1);
334 void div(dpoly& d, Vector *count, ZZ& sign) {
335 int len = coeff->NbRows;
336 Matrix * c = Matrix_Alloc(coeff->NbRows, coeff->NbColumns);
337 Value tmp;
338 value_init(tmp);
339 for (int i = 0; i < len; ++i) {
340 Vector_Copy(coeff->p[i], c->p[i], len+1);
341 for (int j = 1; j <= i; ++j) {
342 zz2value(d.coeff[j], tmp);
343 value_multiply(tmp, tmp, c->p[i][len]);
344 value_oppose(tmp, tmp);
345 Vector_Combine(c->p[i], c->p[i-j], c->p[i],
346 c->p[i-j][len], tmp, len);
347 value_multiply(c->p[i][len], c->p[i][len], c->p[i-j][len]);
349 zz2value(d.coeff[0], tmp);
350 value_multiply(c->p[i][len], c->p[i][len], tmp);
352 if (sign == -1) {
353 value_set_si(tmp, -1);
354 Vector_Scale(c->p[len-1], count->p, tmp, len);
355 value_assign(count->p[len], c->p[len-1][len]);
356 } else
357 Vector_Copy(c->p[len-1], count->p, len+1);
358 Vector_Normalize(count->p, len+1);
359 value_clear(tmp);
360 Matrix_Free(c);
365 * Barvinok's Decomposition of a simplicial cone
367 * Returns two lists of polyhedra
369 void barvinok_decompose(Polyhedron *C, Polyhedron **ppos, Polyhedron **pneg)
371 Polyhedron *pos = *ppos, *neg = *pneg;
372 vector<cone *> nonuni;
373 cone * c = new cone(C);
374 ZZ det = c->det;
375 int s = sign(det);
376 assert(det != 0);
377 if (abs(det) > 1) {
378 nonuni.push_back(c);
379 } else {
380 Polyhedron *p = Polyhedron_Copy(c->Cone);
381 p->next = pos;
382 pos = p;
383 delete c;
385 vec_ZZ lambda;
386 while (!nonuni.empty()) {
387 c = nonuni.back();
388 nonuni.pop_back();
389 Vector* v = c->short_vector(lambda);
390 for (int i = 0; i < c->Rays->NbRows - 1; ++i) {
391 if (lambda[i] == 0)
392 continue;
393 Matrix* M = Matrix_Copy(c->Rays);
394 Vector_Copy(v->p, M->p[i], v->Size);
395 cone * pc = new cone(M);
396 assert (pc->det != 0);
397 if (abs(pc->det) > 1) {
398 assert(abs(pc->det) < abs(c->det));
399 nonuni.push_back(pc);
400 } else {
401 Polyhedron *p = pc->poly();
402 pc->Cone = 0;
403 if (sign(pc->det) == s) {
404 p->next = pos;
405 pos = p;
406 } else {
407 p->next = neg;
408 neg = p;
410 delete pc;
412 Matrix_Free(M);
414 Vector_Free(v);
415 delete c;
417 *ppos = pos;
418 *pneg = neg;
422 * Returns a single list of npos "positive" cones followed by nneg
423 * "negative" cones.
424 * The input cone is freed
426 void decompose(Polyhedron *cone, Polyhedron **parts, int *npos, int *nneg, unsigned MaxRays)
428 Polyhedron_Polarize(cone);
429 if (cone->NbRays - 1 != cone->Dimension) {
430 Polyhedron *tmp = cone;
431 cone = triangularize_cone(cone, MaxRays);
432 Polyhedron_Free(tmp);
434 Polyhedron *polpos = NULL, *polneg = NULL;
435 *npos = 0; *nneg = 0;
436 for (Polyhedron *Polar = cone; Polar; Polar = Polar->next)
437 barvinok_decompose(Polar, &polpos, &polneg);
439 Polyhedron *last;
440 for (Polyhedron *i = polpos; i; i = i->next) {
441 Polyhedron_Polarize(i);
442 ++*npos;
443 last = i;
445 for (Polyhedron *i = polneg; i; i = i->next) {
446 Polyhedron_Polarize(i);
447 ++*nneg;
449 if (last) {
450 last->next = polneg;
451 *parts = polpos;
452 } else
453 *parts = polneg;
454 Domain_Free(cone);
457 const int MAX_TRY=10;
459 * Searches for a vector that is not othogonal to any
460 * of the rays in rays.
462 static void nonorthog(mat_ZZ& rays, vec_ZZ& lambda)
464 int dim = rays.NumCols();
465 bool found = false;
466 lambda.SetLength(dim);
467 for (int i = 2; !found && i <= 50*dim; i+=4) {
468 for (int j = 0; j < MAX_TRY; ++j) {
469 for (int k = 0; k < dim; ++k) {
470 int r = random_int(i)+2;
471 int v = (2*(r%2)-1) * (r >> 1);
472 lambda[k] = v;
474 int k = 0;
475 for (; k < rays.NumRows(); ++k)
476 if (lambda * rays[k] == 0)
477 break;
478 if (k == rays.NumRows()) {
479 found = true;
480 break;
484 assert(found);
487 static void add_rays(mat_ZZ& rays, Polyhedron *i, int *r)
489 unsigned dim = i->Dimension;
490 for (int k = 0; k < i->NbRays; ++k) {
491 if (!value_zero_p(i->Ray[k][dim+1]))
492 continue;
493 values2zz(i->Ray[k]+1, rays[(*r)++], dim);
497 void lattice_point(Value* values, Polyhedron *i, vec_ZZ& lambda, ZZ& num)
499 vec_ZZ vertex;
500 unsigned dim = i->Dimension;
501 if(!value_one_p(values[dim])) {
502 Matrix* Rays = rays(i);
503 Matrix *inv = Matrix_Alloc(Rays->NbRows, Rays->NbColumns);
504 int ok = Matrix_Inverse(Rays, inv);
505 assert(ok);
506 Matrix_Free(Rays);
507 Rays = rays(i);
508 Vector *lambda = Vector_Alloc(dim+1);
509 Vector_Matrix_Product(values, inv, lambda->p);
510 Matrix_Free(inv);
511 for (int j = 0; j < dim; ++j)
512 mpz_cdiv_q(lambda->p[j], lambda->p[j], lambda->p[dim]);
513 value_set_si(lambda->p[dim], 1);
514 Vector *A = Vector_Alloc(dim+1);
515 Vector_Matrix_Product(lambda->p, Rays, A->p);
516 Vector_Free(lambda);
517 Matrix_Free(Rays);
518 values2zz(A->p, vertex, dim);
519 Vector_Free(A);
520 } else
521 values2zz(values, vertex, dim);
523 num = vertex * lambda;
526 static EhrhartPolynom *term(string param, ZZ& c, Value *den = NULL)
528 evalue EP;
529 deque<string> params;
530 value_init(EP.d);
531 value_set_si(EP.d,0);
532 EP.x.p = new_enode(polynomial, 2, 1);
533 value_set_si(EP.x.p->arr[0].d, 1);
534 value_set_si(EP.x.p->arr[0].x.n, 0);
535 if (den == NULL)
536 value_set_si(EP.x.p->arr[1].d, 1);
537 else
538 value_assign(EP.x.p->arr[1].d, *den);
539 zz2value(c, EP.x.p->arr[1].x.n);
540 params.push_back(param);
541 EhrhartPolynom * ret = new EhrhartPolynom(&EP, params);
542 free_evalue_refs(&EP);
543 return ret;
546 static void vertex_period(deque<string>& params,
547 Polyhedron *i, vec_ZZ& lambda, Matrix *T,
548 Value lcm, int p, Vector *val,
549 EhrhartPolynom *E, evalue* ev,
550 ZZ& offset)
552 unsigned nparam = T->NbRows - 1;
553 unsigned dim = i->Dimension;
554 Value tmp;
555 value_init(tmp);
556 ZZ nump;
558 if (p == nparam) {
559 ZZ num, l;
560 Vector * values = Vector_Alloc(dim + 1);
561 Vector_Matrix_Product(val->p, T, values->p);
562 value_assign(values->p[dim], lcm);
563 lattice_point(values->p, i, lambda, num);
564 value2zz(lcm, l);
565 num *= l;
566 num += offset;
567 zz2value(num, ev->x.n);
568 value_assign(ev->d, lcm);
569 Vector_Free(values);
570 return;
573 vec_ZZ vertex;
574 values2zz(T->p[p], vertex, dim);
575 nump = vertex * lambda;
576 if (First_Non_Zero(val->p, p) == -1) {
577 value_assign(tmp, lcm);
578 EhrhartPolynom * ET = term(params[p], nump, &tmp);
579 *E += *ET;
580 delete ET;
583 value_assign(tmp, lcm);
584 if (First_Non_Zero(T->p[p], dim) != -1)
585 Vector_Gcd(T->p[p], dim, &tmp);
586 if (value_lt(tmp, lcm)) {
587 ZZ count;
589 value_division(tmp, lcm, tmp);
590 value_set_si(ev->d, 0);
591 ev->x.p = new_enode(periodic, VALUE_TO_INT(tmp), p+1);
592 value2zz(tmp, count);
593 do {
594 value_decrement(tmp, tmp);
595 --count;
596 ZZ new_offset = offset - count * nump;
597 value_assign(val->p[p], tmp);
598 vertex_period(params, i, lambda, T, lcm, p+1, val, E,
599 &ev->x.p->arr[VALUE_TO_INT(tmp)], new_offset);
600 } while (value_pos_p(tmp));
601 } else
602 vertex_period(params, i, lambda, T, lcm, p+1, val, E, ev, offset);
603 value_clear(tmp);
606 static EhrhartPolynom *multi_mononom(deque<string>& params, vec_ZZ& p)
608 EhrhartPolynom *X = new EhrhartPolynom();
609 unsigned nparam = p.length()-1;
610 for (int i = 0; i < nparam; ++i) {
611 EhrhartPolynom *T = term(params[i], p[i]);
612 *X += *T;
613 delete T;
615 return X;
618 struct term_info {
619 EhrhartPolynom *E;
620 ZZ constant;
621 ZZ coeff;
622 int pos;
625 void lattice_point(deque<string>& params,
626 Param_Vertices* V, Polyhedron *i, vec_ZZ& lambda, term_info* term)
628 unsigned nparam = V->Vertex->NbColumns - 2;
629 unsigned dim = i->Dimension;
630 mat_ZZ vertex;
631 vertex.SetDims(V->Vertex->NbRows, nparam+1);
632 Value lcm, tmp;
633 value_init(lcm);
634 value_init(tmp);
635 value_set_si(lcm, 1);
636 for (int j = 0; j < V->Vertex->NbRows; ++j) {
637 value_lcm(lcm, V->Vertex->p[j][nparam+1], &lcm);
639 if (value_notone_p(lcm)) {
640 Matrix* Rays = rays(i);
641 Matrix *inv = Matrix_Alloc(Rays->NbRows, Rays->NbColumns);
642 int ok = Matrix_Inverse(Rays, inv);
643 assert(ok);
644 Matrix_Free(Rays);
645 Rays = rays(i);
647 Matrix * mv = Matrix_Alloc(dim, nparam+1);
648 for (int j = 0 ; j < dim; ++j) {
649 value_division(tmp, lcm, V->Vertex->p[j][nparam+1]);
650 Vector_Scale(V->Vertex->p[j], mv->p[j], tmp, nparam+1);
652 Matrix *T = Transpose(mv);
654 EhrhartPolynom * EP = new EhrhartPolynom();
655 evalue ev;
656 Vector *val = Vector_Alloc(nparam+1);
657 value_set_si(val->p[nparam], 1);
658 ZZ offset(INIT_VAL, 0);
659 vertex_period(params, i, lambda, T, lcm, 0, val, EP, &ev, offset);
660 Vector_Free(val);
662 *EP += EhrhartPolynom(&ev, params);
664 term->E = EP;
665 term->constant = 0;
667 return;
669 for (int i = 0; i < V->Vertex->NbRows; ++i) {
670 assert(value_one_p(V->Vertex->p[i][nparam+1])); // for now
671 values2zz(V->Vertex->p[i], vertex[i], nparam+1);
674 vec_ZZ num;
675 num = lambda * vertex;
677 int p = -1;
678 int nn = 0;
679 for (int j = 0; j < nparam; ++j)
680 if (num[j] != 0) {
681 ++nn;
682 p = j;
684 if (nn >= 2) {
685 term->E = multi_mononom(params, num);
686 term->constant = num[nparam];
687 } else {
688 term->E = NULL;
689 term->constant = num[nparam];
690 term->pos = p;
691 if (p != -1)
692 term->coeff = num[p];
695 value_clear(lcm);
696 value_clear(tmp);
699 void normalize(Polyhedron *i, vec_ZZ& lambda, ZZ& sign, ZZ& num, vec_ZZ& den)
701 unsigned dim = i->Dimension;
703 int r = 0;
704 mat_ZZ rays;
705 rays.SetDims(dim, dim);
706 add_rays(rays, i, &r);
707 den = rays * lambda;
708 int change = 0;
710 for (int j = 0; j < den.length(); ++j) {
711 if (den[j] > 0)
712 change ^= 1;
713 else {
714 den[j] = abs(den[j]);
715 num += den[j];
718 if (change)
719 sign = -sign;
722 void barvinok_count(Polyhedron *P, Value* result, unsigned NbMaxCons)
724 Polyhedron ** vcone;
725 vec_ZZ sign;
726 int ncone = 0;
727 sign.SetLength(ncone);
728 unsigned dim;
729 int allocated = 0;
730 Value factor;
731 Polyhedron *Q;
732 int r = 0;
734 if (emptyQ(P)) {
735 value_set_si(*result, 0);
736 return;
738 if (P->NbBid == 0)
739 for (; r < P->NbRays; ++r)
740 if (value_zero_p(P->Ray[r][P->Dimension+1]))
741 break;
742 if (P->NbBid !=0 || r < P->NbRays) {
743 value_set_si(*result, -1);
744 return;
746 if (P->NbEq != 0) {
747 P = remove_equalities(P);
748 if (emptyQ(P)) {
749 Polyhedron_Free(P);
750 value_set_si(*result, 0);
751 return;
753 allocated = 1;
755 value_init(factor);
756 value_set_si(factor, 1);
757 Q = Polyhedron_Reduce(P, &factor);
758 if (Q) {
759 if (allocated)
760 Polyhedron_Free(P);
761 P = Q;
762 allocated = 1;
764 if (P->Dimension == 0) {
765 value_assign(*result, factor);
766 if (allocated)
767 Polyhedron_Free(P);
768 value_clear(factor);
769 return;
772 dim = P->Dimension;
773 vcone = new (Polyhedron *)[P->NbRays];
775 for (int j = 0; j < P->NbRays; ++j) {
776 int npos, nneg;
777 Polyhedron *C = supporting_cone(P, j);
778 decompose(C, &vcone[j], &npos, &nneg, NbMaxCons);
779 ncone += npos + nneg;
780 sign.SetLength(ncone);
781 for (int k = 0; k < npos; ++k)
782 sign[ncone-nneg-k-1] = 1;
783 for (int k = 0; k < nneg; ++k)
784 sign[ncone-k-1] = -1;
787 mat_ZZ rays;
788 rays.SetDims(ncone * dim, dim);
789 r = 0;
790 for (int j = 0; j < P->NbRays; ++j) {
791 for (Polyhedron *i = vcone[j]; i; i = i->next) {
792 assert(i->NbRays-1 == dim);
793 add_rays(rays, i, &r);
796 vec_ZZ lambda;
797 nonorthog(rays, lambda);
799 vec_ZZ num;
800 mat_ZZ den;
801 num.SetLength(ncone);
802 den.SetDims(ncone,dim);
804 int f = 0;
805 for (int j = 0; j < P->NbRays; ++j) {
806 for (Polyhedron *i = vcone[j]; i; i = i->next) {
807 lattice_point(P->Ray[j]+1, i, lambda, num[f]);
808 normalize(i, lambda, sign[f], num[f], den[f]);
809 ++f;
812 ZZ min = num[0];
813 for (int j = 1; j < num.length(); ++j)
814 if (num[j] < min)
815 min = num[j];
816 for (int j = 0; j < num.length(); ++j)
817 num[j] -= min;
819 f = 0;
820 mpq_t count;
821 mpq_init(count);
822 for (int j = 0; j < P->NbRays; ++j) {
823 for (Polyhedron *i = vcone[j]; i; i = i->next) {
824 dpoly d(dim, num[f]);
825 dpoly n(dim, den[f][0], 1);
826 for (int k = 1; k < dim; ++k) {
827 dpoly fact(dim, den[f][k], 1);
828 n *= fact;
830 d.div(n, count, sign[f]);
831 ++f;
834 assert(value_one_p(&count[0]._mp_den));
835 value_multiply(*result, &count[0]._mp_num, factor);
836 mpq_clear(count);
838 for (int j = 0; j < P->NbRays; ++j)
839 Domain_Free(vcone[j]);
841 delete [] vcone;
843 if (allocated)
844 Polyhedron_Free(P);
845 value_clear(factor);
848 static void default_params(deque<string>& params, int n)
850 for (int i = 1; i <= n; ++i) {
851 ostringstream s;
852 s << "p" << i;
853 params.push_back(s.str());
857 static EhrhartPolynom *uni_polynom(string param, Vector *c)
859 evalue EP;
860 deque<string> params;
861 unsigned dim = c->Size-2;
862 value_init(EP.d);
863 value_set_si(EP.d,0);
864 EP.x.p = new_enode(polynomial, dim+1, 1);
865 for (int j = 0; j <= dim; ++j) {
866 value_assign(EP.x.p->arr[j].d, c->p[dim+1]);
867 value_assign(EP.x.p->arr[j].x.n, c->p[j]);
869 params.push_back(param);
870 EhrhartPolynom * ret = new EhrhartPolynom(&EP, params);
871 free_evalue_refs(&EP);
872 return ret;
875 static EhrhartPolynom *multi_polynom(deque<string>& params, Vector *c, EhrhartPolynom& X)
877 unsigned dim = c->Size-2;
878 evalue EC;
879 value_init(EC.d);
880 value_init(EC.x.n);
881 value_assign(EC.d, c->p[dim+1]);
883 EhrhartPolynom *res = new EhrhartPolynom();
884 value_assign(EC.x.n, c->p[dim]);
885 *res += EhrhartPolynom(&EC, params);
886 for (int i = dim-1; i >= 0; --i) {
887 *res *= X;
888 value_assign(EC.x.n, c->p[i]);
889 *res += EhrhartPolynom(&EC, params);
891 free_evalue_refs(&EC);
892 return res;
895 static EhrhartPolynom *constant(mpq_t c)
897 evalue EP;
898 deque<string> params;
899 value_init(EP.d);
900 value_init(EP.x.n);
901 value_assign(EP.d, &c[0]._mp_den);
902 value_assign(EP.x.n, &c[0]._mp_num);
903 EhrhartPolynom * ret = new EhrhartPolynom(&EP, params);
904 free_evalue_refs(&EP);
905 return ret;
908 Enumeration* barvinok_enumerate(Polyhedron *P, Polyhedron* C, unsigned MaxRays)
910 Polyhedron *CEq;
911 Matrix *CT;
912 Param_Polyhedron *PP;
913 Param_Domain *D;
914 Param_Vertices *V;
915 Enumeration *en, *res;
916 int r = 0;
917 unsigned nparam = C->Dimension;
919 res = NULL;
921 if (P->NbEq != 0) {
922 Matrix *f;
923 P = remove_equalities_p(P, P->Dimension-nparam, &f);
924 // ignore f for now
925 Matrix_Free(f);
928 assert(C->Dimension != 0); // assume that there are parameters for now
929 PP = Polyhedron2Param_SimplifiedDomain(&P,C,MaxRays,&CEq,&CT);
930 assert(isIdentity(CT)); // assume for now
932 deque<string> params;
933 default_params(params, nparam);
934 unsigned dim = P->Dimension - nparam;
935 Polyhedron ** vcone = new (Polyhedron *)[PP->nbV];
936 int * npos = new int[PP->nbV];
937 int * nneg = new int[PP->nbV];
938 vec_ZZ sign;
940 int i;
941 for (i = 0, V = PP->V; V; ++i, V = V->next) {
942 Polyhedron *C = supporting_cone_p(P, V);
943 decompose(C, &vcone[i], &npos[i], &nneg[i], MaxRays);
946 Vector *c = Vector_Alloc(dim+2);
948 for(D=PP->D;D;D=D->next) {
949 int ncone = 0;
950 sign.SetLength(ncone);
951 FORALL_PVertex_in_ParamPolyhedron(V,D,PP) // _i is internal counter
952 ncone += npos[_i] + nneg[_i];
953 sign.SetLength(ncone);
954 for (int k = 0; k < npos[_i]; ++k)
955 sign[ncone-nneg[_i]-k-1] = 1;
956 for (int k = 0; k < nneg[_i]; ++k)
957 sign[ncone-k-1] = -1;
958 END_FORALL_PVertex_in_ParamPolyhedron;
960 mat_ZZ rays;
961 rays.SetDims(ncone * dim, dim);
962 r = 0;
963 FORALL_PVertex_in_ParamPolyhedron(V,D,PP) // _i is internal counter
964 for (Polyhedron *i = vcone[_i]; i; i = i->next) {
965 assert(i->NbRays-1 == dim);
966 add_rays(rays, i, &r);
968 END_FORALL_PVertex_in_ParamPolyhedron;
969 vec_ZZ lambda;
970 nonorthog(rays, lambda);
972 mat_ZZ den;
973 den.SetDims(ncone,dim);
974 term_info *num = new term_info[ncone];
976 int f = 0;
977 FORALL_PVertex_in_ParamPolyhedron(V,D,PP)
978 for (Polyhedron *i = vcone[_i]; i; i = i->next) {
979 lattice_point(params, V, i, lambda, &num[f]);
980 normalize(i, lambda, sign[f], num[f].constant, den[f]);
981 ++f;
983 END_FORALL_PVertex_in_ParamPolyhedron;
984 ZZ min = num[0].constant;
985 for (int j = 1; j < ncone; ++j)
986 if (num[j].constant < min)
987 min = num[j].constant;
988 for (int j = 0; j < ncone; ++j)
989 num[j].constant -= min;
990 f = 0;
991 EhrhartPolynom EP;
992 mpq_t count;
993 mpq_init(count);
994 FORALL_PVertex_in_ParamPolyhedron(V,D,PP)
995 for (Polyhedron *i = vcone[_i]; i; i = i->next) {
996 dpoly n(dim, den[f][0], 1);
997 for (int k = 1; k < dim; ++k) {
998 dpoly fact(dim, den[f][k], 1);
999 n *= fact;
1001 if (num[f].E != NULL) {
1002 ZZ one(INIT_VAL, 1);
1003 dpoly_n d(dim, num[f].constant, one);
1004 d.div(n, c, sign[f]);
1005 EhrhartPolynom *ET = multi_polynom(params, c, *num[f].E);
1006 EP += *ET;
1007 delete ET;
1008 delete num[f].E;
1009 } else if (num[f].pos != -1) {
1010 dpoly_n d(dim, num[f].constant, num[f].coeff);
1011 d.div(n, c, sign[f]);
1012 EhrhartPolynom *E = uni_polynom(params[num[f].pos], c);
1013 EP += *E;
1014 delete E;
1015 } else {
1016 mpq_set_si(count, 0, 1);
1017 dpoly d(dim, num[f].constant);
1018 d.div(n, count, sign[f]);
1019 EhrhartPolynom *E = constant(count);
1020 EP += *E;
1021 delete E;
1023 ++f;
1025 END_FORALL_PVertex_in_ParamPolyhedron;
1027 mpq_clear(count);
1028 delete [] num;
1030 en = (Enumeration *)malloc(sizeof(Enumeration));
1031 en->next = res;
1032 res = en;
1033 res->ValidityDomain = D->Domain;
1034 res->EP = EP.to_evalue(params);
1035 reduce_evalue(&res->EP);
1038 Vector_Free(c);
1040 for (int j = 0; j < PP->nbV; ++j)
1041 Domain_Free(vcone[j]);
1042 delete [] vcone;
1043 delete [] npos;
1044 delete [] nneg;
1046 return res;