pick up modified versions
[barvinok.git] / barvinok.cc
blob0f6f67942e7ca33cf28b52ef7ec8badd3f255c5c
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 <util.h>
11 extern "C" {
12 #include <polylib/polylibgmp.h>
13 #include "ev_operations.h"
15 #include <barvinok.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 evalue *term(int param, ZZ& c, Value *den = NULL)
528 evalue *EP = new evalue();
529 value_init(EP->d);
530 value_set_si(EP->d,0);
531 EP->x.p = new_enode(polynomial, 2, param + 1);
532 evalue_set_si(&EP->x.p->arr[0], 0, 1);
533 value_init(EP->x.p->arr[1].x.n);
534 if (den == NULL)
535 value_set_si(EP->x.p->arr[1].d, 1);
536 else
537 value_assign(EP->x.p->arr[1].d, *den);
538 zz2value(c, EP->x.p->arr[1].x.n);
539 return EP;
542 static void vertex_period(
543 Polyhedron *i, vec_ZZ& lambda, Matrix *T,
544 Value lcm, int p, Vector *val,
545 evalue *E, evalue* ev,
546 ZZ& offset)
548 unsigned nparam = T->NbRows - 1;
549 unsigned dim = i->Dimension;
550 Value tmp;
551 ZZ nump;
553 if (p == nparam) {
554 ZZ num, l;
555 Vector * values = Vector_Alloc(dim + 1);
556 Vector_Matrix_Product(val->p, T, values->p);
557 value_assign(values->p[dim], lcm);
558 lattice_point(values->p, i, lambda, num);
559 value2zz(lcm, l);
560 num *= l;
561 num += offset;
562 value_init(ev->x.n);
563 zz2value(num, ev->x.n);
564 value_assign(ev->d, lcm);
565 Vector_Free(values);
566 return;
569 value_init(tmp);
570 vec_ZZ vertex;
571 values2zz(T->p[p], vertex, dim);
572 nump = vertex * lambda;
573 if (First_Non_Zero(val->p, p) == -1) {
574 value_assign(tmp, lcm);
575 evalue *ET = term(p, nump, &tmp);
576 eadd(ET, E);
577 free_evalue_refs(ET);
578 delete ET;
581 value_assign(tmp, lcm);
582 if (First_Non_Zero(T->p[p], dim) != -1)
583 Vector_Gcd(T->p[p], dim, &tmp);
584 Gcd(tmp, lcm, &tmp);
585 if (value_lt(tmp, lcm)) {
586 ZZ count;
588 value_division(tmp, lcm, tmp);
589 value_set_si(ev->d, 0);
590 ev->x.p = new_enode(periodic, VALUE_TO_INT(tmp), p+1);
591 value2zz(tmp, count);
592 do {
593 value_decrement(tmp, tmp);
594 --count;
595 ZZ new_offset = offset - count * nump;
596 value_assign(val->p[p], tmp);
597 vertex_period(i, lambda, T, lcm, p+1, val, E,
598 &ev->x.p->arr[VALUE_TO_INT(tmp)], new_offset);
599 } while (value_pos_p(tmp));
600 } else
601 vertex_period(i, lambda, T, lcm, p+1, val, E, ev, offset);
602 value_clear(tmp);
605 static void mask_r(Matrix *f, int nr, Vector *lcm, int p, Vector *val, evalue *ev)
607 unsigned nparam = lcm->Size;
609 if (p == nparam) {
610 Vector * prod = Vector_Alloc(f->NbRows);
611 Matrix_Vector_Product(f, val->p, prod->p);
612 int isint = 1;
613 for (int i = 0; i < nr; ++i) {
614 value_modulus(prod->p[i], prod->p[i], f->p[i][nparam+1]);
615 isint &= value_zero_p(prod->p[i]);
617 value_set_si(ev->d, 1);
618 value_init(ev->x.n);
619 value_set_si(ev->x.n, isint);
620 Vector_Free(prod);
621 return;
624 Value tmp;
625 value_init(tmp);
626 if (value_one_p(lcm->p[p]))
627 mask_r(f, nr, lcm, p+1, val, ev);
628 else {
629 value_assign(tmp, lcm->p[p]);
630 value_set_si(ev->d, 0);
631 ev->x.p = new_enode(periodic, VALUE_TO_INT(tmp), p+1);
632 do {
633 value_decrement(tmp, tmp);
634 value_assign(val->p[p], tmp);
635 mask_r(f, nr, lcm, p+1, val, &ev->x.p->arr[VALUE_TO_INT(tmp)]);
636 } while (value_pos_p(tmp));
638 value_clear(tmp);
644 static void mask(Matrix *f, evalue *factor)
646 int nr = f->NbRows, nc = f->NbColumns;
647 int n;
648 bool found = false;
649 for (n = 0; n < nr && value_notzero_p(f->p[n][nc-1]); ++n)
650 if (value_notone_p(f->p[n][nc-1]) &&
651 value_notmone_p(f->p[n][nc-1]))
652 found = true;
653 if (!found)
654 return;
656 Value tmp;
657 value_init(tmp);
658 nr = n;
659 unsigned np = nc - 2;
660 Vector *lcm = Vector_Alloc(np);
661 Vector *val = Vector_Alloc(nc);
662 Vector_Set(val->p, 0, nc);
663 value_set_si(val->p[np], 1);
664 Vector_Set(lcm->p, 1, np);
665 for (n = 0; n < nr; ++n) {
666 if (value_one_p(f->p[n][nc-1]) ||
667 value_mone_p(f->p[n][nc-1]))
668 continue;
669 for (int j = 0; j < np; ++j)
670 if (value_notzero_p(f->p[n][j])) {
671 Gcd(f->p[n][j], f->p[n][nc-1], &tmp);
672 value_division(tmp, f->p[n][nc-1], tmp);
673 value_lcm(tmp, lcm->p[j], &lcm->p[j]);
676 evalue EP;
677 value_init(EP.d);
678 mask_r(f, nr, lcm, 0, val, &EP);
679 value_clear(tmp);
680 Vector_Free(val);
681 Vector_Free(lcm);
682 emul(&EP,factor);
683 free_evalue_refs(&EP);
686 static evalue *multi_mononom(vec_ZZ& p)
688 evalue *X = new evalue();
689 value_init(X->d);
690 evalue_set_si(X, 0, 1);
691 unsigned nparam = p.length()-1;
692 for (int i = 0; i < nparam; ++i) {
693 evalue *T = term(i, p[i]);
694 eadd(T, X);
695 free_evalue_refs(T);
696 delete T;
698 return X;
701 struct term_info {
702 evalue *E;
703 ZZ constant;
704 ZZ coeff;
705 int pos;
708 void lattice_point(
709 Param_Vertices* V, Polyhedron *i, vec_ZZ& lambda, term_info* term)
711 unsigned nparam = V->Vertex->NbColumns - 2;
712 unsigned dim = i->Dimension;
713 mat_ZZ vertex;
714 vertex.SetDims(V->Vertex->NbRows, nparam+1);
715 Value lcm, tmp;
716 value_init(lcm);
717 value_init(tmp);
718 value_set_si(lcm, 1);
719 for (int j = 0; j < V->Vertex->NbRows; ++j) {
720 value_lcm(lcm, V->Vertex->p[j][nparam+1], &lcm);
722 if (value_notone_p(lcm)) {
723 Matrix* Rays = rays(i);
724 Matrix *inv = Matrix_Alloc(Rays->NbRows, Rays->NbColumns);
725 int ok = Matrix_Inverse(Rays, inv);
726 assert(ok);
727 Matrix_Free(Rays);
728 Rays = rays(i);
730 Matrix * mv = Matrix_Alloc(dim, nparam+1);
731 for (int j = 0 ; j < dim; ++j) {
732 value_division(tmp, lcm, V->Vertex->p[j][nparam+1]);
733 Vector_Scale(V->Vertex->p[j], mv->p[j], tmp, nparam+1);
735 Matrix *T = Transpose(mv);
737 evalue *EP = new evalue();
738 value_init(EP->d);
739 evalue_set_si(EP, 0, 1);
740 evalue ev;
741 Vector *val = Vector_Alloc(nparam+1);
742 value_set_si(val->p[nparam], 1);
743 ZZ offset(INIT_VAL, 0);
744 value_init(ev.d);
745 vertex_period(i, lambda, T, lcm, 0, val, EP, &ev, offset);
746 Vector_Free(val);
747 eadd(&ev, EP);
748 free_evalue_refs(&ev);
750 term->E = EP;
751 term->constant = 0;
753 Matrix_Free(inv);
754 Matrix_Free(Rays);
755 Matrix_Free(T);
756 Matrix_Free(mv);
757 value_clear(lcm);
758 value_clear(tmp);
759 return;
761 for (int i = 0; i < V->Vertex->NbRows; ++i) {
762 assert(value_one_p(V->Vertex->p[i][nparam+1])); // for now
763 values2zz(V->Vertex->p[i], vertex[i], nparam+1);
766 vec_ZZ num;
767 num = lambda * vertex;
769 int p = -1;
770 int nn = 0;
771 for (int j = 0; j < nparam; ++j)
772 if (num[j] != 0) {
773 ++nn;
774 p = j;
776 if (nn >= 2) {
777 term->E = multi_mononom(num);
778 term->constant = num[nparam];
779 } else {
780 term->E = NULL;
781 term->constant = num[nparam];
782 term->pos = p;
783 if (p != -1)
784 term->coeff = num[p];
787 value_clear(lcm);
788 value_clear(tmp);
791 void normalize(Polyhedron *i, vec_ZZ& lambda, ZZ& sign, ZZ& num, vec_ZZ& den)
793 unsigned dim = i->Dimension;
795 int r = 0;
796 mat_ZZ rays;
797 rays.SetDims(dim, dim);
798 add_rays(rays, i, &r);
799 den = rays * lambda;
800 int change = 0;
802 for (int j = 0; j < den.length(); ++j) {
803 if (den[j] > 0)
804 change ^= 1;
805 else {
806 den[j] = abs(den[j]);
807 num += den[j];
810 if (change)
811 sign = -sign;
814 void barvinok_count(Polyhedron *P, Value* result, unsigned NbMaxCons)
816 Polyhedron ** vcone;
817 vec_ZZ sign;
818 int ncone = 0;
819 sign.SetLength(ncone);
820 unsigned dim;
821 int allocated = 0;
822 Value factor;
823 Polyhedron *Q;
824 int r = 0;
826 if (emptyQ(P)) {
827 value_set_si(*result, 0);
828 return;
830 if (P->NbBid == 0)
831 for (; r < P->NbRays; ++r)
832 if (value_zero_p(P->Ray[r][P->Dimension+1]))
833 break;
834 if (P->NbBid !=0 || r < P->NbRays) {
835 value_set_si(*result, -1);
836 return;
838 if (P->NbEq != 0) {
839 P = remove_equalities(P);
840 if (emptyQ(P)) {
841 Polyhedron_Free(P);
842 value_set_si(*result, 0);
843 return;
845 allocated = 1;
847 value_init(factor);
848 value_set_si(factor, 1);
849 Q = Polyhedron_Reduce(P, &factor);
850 if (Q) {
851 if (allocated)
852 Polyhedron_Free(P);
853 P = Q;
854 allocated = 1;
856 if (P->Dimension == 0) {
857 value_assign(*result, factor);
858 if (allocated)
859 Polyhedron_Free(P);
860 value_clear(factor);
861 return;
864 dim = P->Dimension;
865 vcone = new (Polyhedron *)[P->NbRays];
867 for (int j = 0; j < P->NbRays; ++j) {
868 int npos, nneg;
869 Polyhedron *C = supporting_cone(P, j);
870 decompose(C, &vcone[j], &npos, &nneg, NbMaxCons);
871 ncone += npos + nneg;
872 sign.SetLength(ncone);
873 for (int k = 0; k < npos; ++k)
874 sign[ncone-nneg-k-1] = 1;
875 for (int k = 0; k < nneg; ++k)
876 sign[ncone-k-1] = -1;
879 mat_ZZ rays;
880 rays.SetDims(ncone * dim, dim);
881 r = 0;
882 for (int j = 0; j < P->NbRays; ++j) {
883 for (Polyhedron *i = vcone[j]; i; i = i->next) {
884 assert(i->NbRays-1 == dim);
885 add_rays(rays, i, &r);
888 vec_ZZ lambda;
889 nonorthog(rays, lambda);
891 vec_ZZ num;
892 mat_ZZ den;
893 num.SetLength(ncone);
894 den.SetDims(ncone,dim);
896 int f = 0;
897 for (int j = 0; j < P->NbRays; ++j) {
898 for (Polyhedron *i = vcone[j]; i; i = i->next) {
899 lattice_point(P->Ray[j]+1, i, lambda, num[f]);
900 normalize(i, lambda, sign[f], num[f], den[f]);
901 ++f;
904 ZZ min = num[0];
905 for (int j = 1; j < num.length(); ++j)
906 if (num[j] < min)
907 min = num[j];
908 for (int j = 0; j < num.length(); ++j)
909 num[j] -= min;
911 f = 0;
912 mpq_t count;
913 mpq_init(count);
914 for (int j = 0; j < P->NbRays; ++j) {
915 for (Polyhedron *i = vcone[j]; i; i = i->next) {
916 dpoly d(dim, num[f]);
917 dpoly n(dim, den[f][0], 1);
918 for (int k = 1; k < dim; ++k) {
919 dpoly fact(dim, den[f][k], 1);
920 n *= fact;
922 d.div(n, count, sign[f]);
923 ++f;
926 assert(value_one_p(&count[0]._mp_den));
927 value_multiply(*result, &count[0]._mp_num, factor);
928 mpq_clear(count);
930 for (int j = 0; j < P->NbRays; ++j)
931 Domain_Free(vcone[j]);
933 delete [] vcone;
935 if (allocated)
936 Polyhedron_Free(P);
937 value_clear(factor);
940 static void uni_polynom(int param, Vector *c, evalue *EP)
942 unsigned dim = c->Size-2;
943 value_init(EP->d);
944 value_set_si(EP->d,0);
945 EP->x.p = new_enode(polynomial, dim+1, param+1);
946 for (int j = 0; j <= dim; ++j)
947 evalue_set(&EP->x.p->arr[j], c->p[j], c->p[dim+1]);
950 static void multi_polynom(Vector *c, evalue* X, evalue *EP)
952 unsigned dim = c->Size-2;
953 evalue EC;
955 value_init(EC.d);
956 evalue_set(&EC, c->p[dim], c->p[dim+1]);
958 value_init(EP->d);
959 evalue_set(EP, c->p[dim], c->p[dim+1]);
961 for (int i = dim-1; i >= 0; --i) {
962 emul(X, EP);
963 value_assign(EC.x.n, c->p[i]);
964 eadd(&EC, EP);
966 free_evalue_refs(&EC);
970 Enumeration* barvinok_enumerate(Polyhedron *P, Polyhedron* C, unsigned MaxRays)
972 Polyhedron *CEq = NULL, *rVD, *CA;
973 Matrix *CT = NULL;
974 Param_Polyhedron *PP = NULL;
975 Param_Domain *D, *next;
976 Param_Vertices *V;
977 Enumeration *en, *res;
978 int r = 0;
979 unsigned nparam = C->Dimension;
980 evalue factor;
981 value_init(factor.d);
982 evalue_set_si(&factor, 1, 1);
984 res = NULL;
986 CA = align_context(C, P->Dimension, MaxRays);
987 P = DomainIntersection(P, CA, MaxRays);
988 Polyhedron_Free(CA);
990 if (C->Dimension == 0 || emptyQ(P)) {
991 constant:
992 res = (Enumeration *)malloc(sizeof(Enumeration));
993 res->ValidityDomain = CEq ? CEq : Polyhedron_Copy(C);
994 res->next = NULL;
995 value_init(res->EP.d);
996 value_set_si(res->EP.d, 1);
997 value_init(res->EP.x.n);
998 if (emptyQ(P))
999 value_set_si(res->EP.x.n, 0);
1000 else
1001 barvinok_count(P, &res->EP.x.n, MaxRays);
1002 emul(&factor, &res->EP);
1003 out:
1004 free_evalue_refs(&factor);
1005 Polyhedron_Free(P);
1006 if (CT)
1007 Matrix_Free(CT);
1008 if (PP)
1009 Param_Polyhedron_Free(PP);
1011 return res;
1014 if (P->NbEq != 0) {
1015 Matrix *f;
1016 P = remove_equalities_p(P, P->Dimension-nparam, &f);
1017 mask(f, &factor);
1018 Matrix_Free(f);
1019 if (P->Dimension == nparam) {
1020 CEq = P;
1021 P = Universe_Polyhedron(0);
1022 goto constant;
1025 Polyhedron *oldP = P;
1026 PP = Polyhedron2Param_SimplifiedDomain(&P,C,MaxRays,&CEq,&CT);
1027 if (P != oldP)
1028 Polyhedron_Free(oldP);
1030 if (isIdentity(CT)) {
1031 Matrix_Free(CT);
1032 CT = NULL;
1033 } else {
1034 assert(CT->NbRows != CT->NbColumns);
1035 if (CT->NbRows == 1) // no more parameters
1036 goto constant;
1037 nparam = CT->NbRows - 1;
1040 unsigned dim = P->Dimension - nparam;
1041 Polyhedron ** vcone = new (Polyhedron *)[PP->nbV];
1042 int * npos = new int[PP->nbV];
1043 int * nneg = new int[PP->nbV];
1044 vec_ZZ sign;
1046 int i;
1047 for (i = 0, V = PP->V; V; ++i, V = V->next) {
1048 Polyhedron *C = supporting_cone_p(P, V);
1049 decompose(C, &vcone[i], &npos[i], &nneg[i], MaxRays);
1052 Vector *c = Vector_Alloc(dim+2);
1054 for(D=PP->D; D; D=next) {
1055 next = D->next;
1056 if (!CEq) {
1057 rVD = D->Domain;
1058 D->Domain = NULL;
1059 } else {
1060 Polyhedron *Dt;
1061 Dt = CT ? Polyhedron_Preimage(D->Domain,CT,MaxRays) : D->Domain;
1062 rVD = DomainIntersection(Dt,CEq,MaxRays);
1064 /* if rVD is empty or too small in geometric dimension */
1065 if(!rVD || emptyQ(rVD) ||
1066 (rVD->Dimension-rVD->NbEq < Dt->Dimension-Dt->NbEq-CEq->NbEq)) {
1067 if(rVD)
1068 Polyhedron_Free(rVD);
1069 if (CT)
1070 Polyhedron_Free(Dt);
1071 continue; /* empty validity domain */
1073 if (CT)
1074 Polyhedron_Free(Dt);
1076 int ncone = 0;
1077 sign.SetLength(ncone);
1078 FORALL_PVertex_in_ParamPolyhedron(V,D,PP) // _i is internal counter
1079 ncone += npos[_i] + nneg[_i];
1080 sign.SetLength(ncone);
1081 for (int k = 0; k < npos[_i]; ++k)
1082 sign[ncone-nneg[_i]-k-1] = 1;
1083 for (int k = 0; k < nneg[_i]; ++k)
1084 sign[ncone-k-1] = -1;
1085 END_FORALL_PVertex_in_ParamPolyhedron;
1087 mat_ZZ rays;
1088 rays.SetDims(ncone * dim, dim);
1089 r = 0;
1090 FORALL_PVertex_in_ParamPolyhedron(V,D,PP) // _i is internal counter
1091 for (Polyhedron *i = vcone[_i]; i; i = i->next) {
1092 assert(i->NbRays-1 == dim);
1093 add_rays(rays, i, &r);
1095 END_FORALL_PVertex_in_ParamPolyhedron;
1096 vec_ZZ lambda;
1097 nonorthog(rays, lambda);
1099 mat_ZZ den;
1100 den.SetDims(ncone,dim);
1101 term_info *num = new term_info[ncone];
1103 int f = 0;
1104 FORALL_PVertex_in_ParamPolyhedron(V,D,PP)
1105 for (Polyhedron *i = vcone[_i]; i; i = i->next) {
1106 lattice_point(V, i, lambda, &num[f]);
1107 normalize(i, lambda, sign[f], num[f].constant, den[f]);
1108 ++f;
1110 END_FORALL_PVertex_in_ParamPolyhedron;
1111 ZZ min = num[0].constant;
1112 for (int j = 1; j < ncone; ++j)
1113 if (num[j].constant < min)
1114 min = num[j].constant;
1115 for (int j = 0; j < ncone; ++j)
1116 num[j].constant -= min;
1117 f = 0;
1118 evalue EP;
1119 value_init(EP.d);
1120 evalue_set_si(&EP, 0, 1);
1121 mpq_t count;
1122 mpq_init(count);
1123 FORALL_PVertex_in_ParamPolyhedron(V,D,PP)
1124 for (Polyhedron *i = vcone[_i]; i; i = i->next) {
1125 dpoly n(dim, den[f][0], 1);
1126 for (int k = 1; k < dim; ++k) {
1127 dpoly fact(dim, den[f][k], 1);
1128 n *= fact;
1130 if (num[f].E != NULL) {
1131 ZZ one(INIT_VAL, 1);
1132 dpoly_n d(dim, num[f].constant, one);
1133 d.div(n, c, sign[f]);
1134 evalue EV;
1135 multi_polynom(c, num[f].E, &EV);
1136 eadd(&EV , &EP);
1137 free_evalue_refs(&EV);
1138 free_evalue_refs(num[f].E);
1139 delete num[f].E;
1140 } else if (num[f].pos != -1) {
1141 dpoly_n d(dim, num[f].constant, num[f].coeff);
1142 d.div(n, c, sign[f]);
1143 evalue EV;
1144 uni_polynom(num[f].pos, c, &EV);
1145 eadd(&EV , &EP);
1146 free_evalue_refs(&EV);
1147 } else {
1148 mpq_set_si(count, 0, 1);
1149 dpoly d(dim, num[f].constant);
1150 d.div(n, count, sign[f]);
1151 evalue EV;
1152 value_init(EV.d);
1153 evalue_set(&EV, &count[0]._mp_num, &count[0]._mp_den);
1154 eadd(&EV , &EP);
1155 free_evalue_refs(&EV);
1157 ++f;
1159 END_FORALL_PVertex_in_ParamPolyhedron;
1161 mpq_clear(count);
1162 delete [] num;
1164 en = (Enumeration *)malloc(sizeof(Enumeration));
1165 en->next = res;
1166 res = en;
1167 res->ValidityDomain = rVD;
1168 if (CT)
1169 addeliminatedparams_evalue(&EP, CT);
1170 emul(&factor, &EP);
1171 res->EP = EP;
1172 reduce_evalue(&res->EP);
1175 Vector_Free(c);
1177 for (int j = 0; j < PP->nbV; ++j)
1178 Domain_Free(vcone[j]);
1179 delete [] vcone;
1180 delete [] npos;
1181 delete [] nneg;
1183 if (CEq)
1184 Polyhedron_Free(CEq);
1186 goto out;