lattice_point.cc: extract coset generation
[barvinok.git] / lattice_point.cc
blob0e0b78197491bf35ef8a22db01d779f86697c0a6
1 #include <assert.h>
2 #include <NTL/mat_ZZ.h>
3 #include <NTL/vec_ZZ.h>
4 #include <barvinok/barvinok.h>
5 #include <barvinok/evalue.h>
6 #include <barvinok/util.h>
7 #include "config.h"
8 #include "conversion.h"
9 #include "lattice_point.h"
10 #include "param_util.h"
12 using std::cerr;
13 using std::endl;
15 #define ALLOC(type) (type*)malloc(sizeof(type))
17 /* returns an evalue that corresponds to
19 * c/(*den) x_param
21 static evalue *term(int param, ZZ& c, Value *den = NULL)
23 evalue *EP = new evalue();
24 value_init(EP->d);
25 value_set_si(EP->d,0);
26 EP->x.p = new_enode(polynomial, 2, param + 1);
27 evalue_set_si(&EP->x.p->arr[0], 0, 1);
28 value_init(EP->x.p->arr[1].x.n);
29 if (den == NULL)
30 value_set_si(EP->x.p->arr[1].d, 1);
31 else
32 value_assign(EP->x.p->arr[1].d, *den);
33 zz2value(c, EP->x.p->arr[1].x.n);
34 return EP;
37 /* returns an evalue that corresponds to
39 * sum_i p[i] * x_i
41 evalue *multi_monom(vec_ZZ& p)
43 evalue *X = new evalue();
44 value_init(X->d);
45 value_init(X->x.n);
46 unsigned nparam = p.length()-1;
47 zz2value(p[nparam], X->x.n);
48 value_set_si(X->d, 1);
49 for (int i = 0; i < nparam; ++i) {
50 if (p[i] == 0)
51 continue;
52 evalue *T = term(i, p[i]);
53 eadd(T, X);
54 free_evalue_refs(T);
55 delete T;
57 return X;
61 * Check whether mapping polyhedron P on the affine combination
62 * num yields a range that has a fixed quotient on integer
63 * division by d
64 * If zero is true, then we are only interested in the quotient
65 * for the cases where the remainder is zero.
66 * Returns NULL if false and a newly allocated value if true.
68 static Value *fixed_quotient(Polyhedron *P, vec_ZZ& num, Value d, bool zero)
70 Value* ret = NULL;
71 int len = num.length();
72 Matrix *T = Matrix_Alloc(2, len);
73 zz2values(num, T->p[0]);
74 value_set_si(T->p[1][len-1], 1);
75 Polyhedron *I = Polyhedron_Image(P, T, P->NbConstraints);
76 Matrix_Free(T);
78 int i;
79 for (i = 0; i < I->NbRays; ++i)
80 if (value_zero_p(I->Ray[i][2])) {
81 Polyhedron_Free(I);
82 return NULL;
85 Value min, max;
86 value_init(min);
87 value_init(max);
88 int bounded = line_minmax(I, &min, &max);
89 assert(bounded);
91 if (zero)
92 mpz_cdiv_q(min, min, d);
93 else
94 mpz_fdiv_q(min, min, d);
95 mpz_fdiv_q(max, max, d);
97 if (value_eq(min, max)) {
98 ret = ALLOC(Value);
99 value_init(*ret);
100 value_assign(*ret, min);
102 value_clear(min);
103 value_clear(max);
104 return ret;
108 * Normalize linear expression coef modulo m
109 * Removes common factor and reduces coefficients
110 * Returns index of first non-zero coefficient or len
112 int normal_mod(Value *coef, int len, Value *m)
114 Value gcd;
115 value_init(gcd);
117 Vector_Gcd(coef, len, &gcd);
118 Gcd(gcd, *m, &gcd);
119 Vector_AntiScale(coef, coef, gcd, len);
121 value_division(*m, *m, gcd);
122 value_clear(gcd);
124 if (value_one_p(*m))
125 return len;
127 int j;
128 for (j = 0; j < len; ++j)
129 mpz_fdiv_r(coef[j], coef[j], *m);
130 for (j = 0; j < len; ++j)
131 if (value_notzero_p(coef[j]))
132 break;
134 return j;
137 static bool mod_needed(Polyhedron *PD, vec_ZZ& num, Value d, evalue *E)
139 Value *q = fixed_quotient(PD, num, d, false);
141 if (!q)
142 return true;
144 value_oppose(*q, *q);
145 evalue EV;
146 value_init(EV.d);
147 value_set_si(EV.d, 1);
148 value_init(EV.x.n);
149 value_multiply(EV.x.n, *q, d);
150 eadd(&EV, E);
151 free_evalue_refs(&EV);
152 value_clear(*q);
153 free(q);
154 return false;
157 /* modifies coef argument ! */
158 static void fractional_part(Value *coef, int len, Value d, ZZ& f, evalue *EP,
159 Polyhedron *PD)
161 Value m;
162 value_init(m);
164 value_assign(m, d);
165 int j = normal_mod(coef, len, &m);
167 if (j == len) {
168 value_clear(m);
169 return;
172 vec_ZZ num;
173 values2zz(coef, num, len);
175 ZZ g;
176 value2zz(m, g);
178 evalue tmp;
179 value_init(tmp.d);
180 evalue_set_si(&tmp, 0, 1);
182 int p = j;
183 if (g % 2 == 0)
184 while (j < len-1 && (num[j] == g/2 || num[j] == 0))
185 ++j;
186 if ((j < len-1 && num[j] > g/2) || (j == len-1 && num[j] >= (g+1)/2)) {
187 for (int k = j; k < len-1; ++k)
188 if (num[k] != 0)
189 num[k] = g - num[k];
190 num[len-1] = g - 1 - num[len-1];
191 value_assign(tmp.d, m);
192 ZZ t = f*(g-1);
193 zz2value(t, tmp.x.n);
194 eadd(&tmp, EP);
195 f = -f;
198 if (p >= len-1) {
199 ZZ t = num[len-1] * f;
200 zz2value(t, tmp.x.n);
201 value_assign(tmp.d, m);
202 eadd(&tmp, EP);
203 } else {
204 evalue *E = multi_monom(num);
205 evalue EV;
206 value_init(EV.d);
208 if (PD && !mod_needed(PD, num, m, E)) {
209 value_init(EV.x.n);
210 zz2value(f, EV.x.n);
211 value_assign(EV.d, m);
212 emul(&EV, E);
213 eadd(E, EP);
214 } else {
215 value_init(EV.x.n);
216 value_set_si(EV.x.n, 1);
217 value_assign(EV.d, m);
218 emul(&EV, E);
219 value_clear(EV.x.n);
220 value_set_si(EV.d, 0);
221 EV.x.p = new_enode(fractional, 3, -1);
222 evalue_copy(&EV.x.p->arr[0], E);
223 evalue_set_si(&EV.x.p->arr[1], 0, 1);
224 value_init(EV.x.p->arr[2].x.n);
225 zz2value(f, EV.x.p->arr[2].x.n);
226 value_set_si(EV.x.p->arr[2].d, 1);
228 eadd(&EV, EP);
231 free_evalue_refs(&EV);
232 free_evalue_refs(E);
233 delete E;
236 free_evalue_refs(&tmp);
238 out:
239 value_clear(m);
242 static void ceil(Value *coef, int len, Value d, ZZ& f,
243 evalue *EP, Polyhedron *PD, barvinok_options *options)
245 Vector_Oppose(coef, coef, len);
246 fractional_part(coef, len, d, f, EP, PD);
247 if (options->lookup_table)
248 evalue_mod2table(EP, len-1);
251 evalue* bv_ceil3(Value *coef, int len, Value d, Polyhedron *P)
253 Vector *val = Vector_Alloc(len);
255 Value t;
256 value_init(t);
257 value_set_si(t, -1);
258 Vector_Scale(coef, val->p, t, len);
259 value_absolute(t, d);
261 vec_ZZ num;
262 values2zz(val->p, num, len);
263 evalue *EP = multi_monom(num);
265 evalue tmp;
266 value_init(tmp.d);
267 value_init(tmp.x.n);
268 value_set_si(tmp.x.n, 1);
269 value_assign(tmp.d, t);
271 emul(&tmp, EP);
273 ZZ one;
274 one = 1;
275 Vector_Oppose(val->p, val->p, len);
276 fractional_part(val->p, len, t, one, EP, P);
277 value_clear(t);
279 /* copy EP to malloc'ed evalue */
280 evalue *E = ALLOC(evalue);
281 *E = *EP;
282 delete EP;
284 free_evalue_refs(&tmp);
285 Vector_Free(val);
287 return E;
290 void lattice_point(Value* values, const mat_ZZ& rays, vec_ZZ& vertex, int *closed)
292 unsigned dim = rays.NumRows();
293 if (value_one_p(values[dim]) && !closed)
294 values2zz(values, vertex, dim);
295 else {
296 Matrix* Rays = rays2matrix(rays);
297 Matrix *inv = Matrix_Alloc(Rays->NbRows, Rays->NbColumns);
298 int ok = Matrix_Inverse(Rays, inv);
299 assert(ok);
300 Matrix_Free(Rays);
301 Rays = rays2matrix(rays);
302 Vector *lambda = Vector_Alloc(dim+1);
303 Vector_Matrix_Product(values, inv, lambda->p);
304 Matrix_Free(inv);
305 for (int j = 0; j < dim; ++j)
306 if (!closed || closed[j])
307 mpz_cdiv_q(lambda->p[j], lambda->p[j], lambda->p[dim]);
308 else {
309 value_addto(lambda->p[j], lambda->p[j], lambda->p[dim]);
310 mpz_fdiv_q(lambda->p[j], lambda->p[j], lambda->p[dim]);
312 value_set_si(lambda->p[dim], 1);
313 Vector *A = Vector_Alloc(dim+1);
314 Vector_Matrix_Product(lambda->p, Rays, A->p);
315 Vector_Free(lambda);
316 Matrix_Free(Rays);
317 values2zz(A->p, vertex, dim);
318 Vector_Free(A);
322 #define FORALL_COSETS(det,D,i,k) \
323 do { \
324 Vector *k = Vector_Alloc(D->NbRows+1); \
325 value_set_si(k->p[D->NbRows], 1); \
326 for (unsigned long i = 0; i < det; ++i) { \
327 unsigned long _fc_val = i; \
328 for (int j = 0; j < D->NbRows; ++j) { \
329 value_set_si(k->p[j], _fc_val % mpz_get_ui(D->p[j][j]));\
330 _fc_val /= mpz_get_ui(D->p[j][j]); \
332 #define END_FORALL_COSETS \
334 Vector_Free(k); \
335 } while(0);
337 /* Compute the lattice points in the vertex cone at "values" with rays "rays".
338 * The lattice points are returned in "vertex".
340 * Rays has the generators as rows and so does W.
341 * We first compute { m-v, u_i^* } with m = k W, where k runs through
342 * the cosets.
343 * We compute
344 * [k 1] [ d1*W 0 ] [ U' 0 ] = [k 1] T2
345 * [ -v d1 ] [ 0 d2 ]
346 * where d1 and d2 are the denominators of v and U^{-1}=U'/d2.
347 * Then lambda = { k } (componentwise)
348 * We compute x - floor(x) = {x} = { a/b } as fdiv_r(a,b)/b
349 * For open rays/facets, we need values in (0,1] rather than [0,1),
350 * so we compute {{x}} = x - ceil(x-1) = a/b - ceil((a-b)/b)
351 * = (a - b cdiv_q(a-b,b) - b + b)/b
352 * = (cdiv_r(a,b)+b)/b
353 * Finally, we compute v + lambda * U
354 * The denominator of lambda can be d1*d2, that of lambda2 = lambda*U
355 * can be at most d1, since it is integer if v = 0.
356 * The denominator of v + lambda2 is 1.
358 void lattice_point(Value* values, const mat_ZZ& rays, mat_ZZ& vertex,
359 unsigned long det, int *closed)
361 unsigned dim = rays.NumRows();
362 vertex.SetDims(det, dim);
363 if (det == 1) {
364 lattice_point(values, rays, vertex[0], closed);
365 return;
367 Matrix* Rays = rays2matrix2(rays);
368 Matrix *U, *W, *D;
369 Smith(Rays, &U, &W, &D);
370 Matrix_Free(Rays);
371 Matrix_Free(U);
373 /* Sanity check */
374 unsigned long det2 = 1;
375 for (int i = 0 ; i < D->NbRows; ++i)
376 det2 *= mpz_get_ui(D->p[i][i]);
377 assert(det == det2);
379 Matrix *T = Matrix_Alloc(W->NbRows+1, W->NbColumns+1);
380 for (int i = 0; i < W->NbRows; ++i)
381 Vector_Scale(W->p[i], T->p[i], values[dim], W->NbColumns);
382 Matrix_Free(W);
383 Value tmp;
384 value_init(tmp);
385 value_set_si(tmp, -1);
386 Vector_Scale(values, T->p[dim], tmp, dim);
387 value_clear(tmp);
388 value_assign(T->p[dim][dim], values[dim]);
390 Rays = rays2matrix(rays);
391 Matrix *inv = Matrix_Alloc(Rays->NbRows, Rays->NbColumns);
392 int ok = Matrix_Inverse(Rays, inv);
393 assert(ok);
394 Matrix_Free(Rays);
396 Matrix *T2 = Matrix_Alloc(dim+1, dim+1);
397 Matrix_Product(T, inv, T2);
398 Matrix_Free(T);
400 Rays = rays2matrix(rays);
402 Vector *lambda = Vector_Alloc(dim+1);
403 Vector *lambda2 = Vector_Alloc(dim+1);
404 FORALL_COSETS(det, D, i, k)
405 Vector_Matrix_Product(k->p, T2, lambda->p);
406 for (int j = 0; j < dim; ++j)
407 if (!closed || closed[j])
408 mpz_fdiv_r(lambda->p[j], lambda->p[j], lambda->p[dim]);
409 else {
410 mpz_cdiv_r(lambda->p[j], lambda->p[j], lambda->p[dim]);
411 value_addto(lambda->p[j], lambda->p[j], lambda->p[dim]);
413 Vector_Matrix_Product(lambda->p, Rays, lambda2->p);
414 for (int j = 0; j < dim; ++j)
415 assert(mpz_divisible_p(lambda2->p[j], inv->p[dim][dim]));
416 Vector_AntiScale(lambda2->p, lambda2->p, inv->p[dim][dim], dim+1);
417 Vector_Add(lambda2->p, values, lambda2->p, dim);
418 for (int j = 0; j < dim; ++j)
419 assert(mpz_divisible_p(lambda2->p[j], values[dim]));
420 Vector_AntiScale(lambda2->p, lambda2->p, values[dim], dim+1);
421 values2zz(lambda2->p, vertex[i], dim);
422 END_FORALL_COSETS
423 Vector_Free(lambda);
424 Vector_Free(lambda2);
425 Matrix_Free(D);
426 Matrix_Free(Rays);
427 Matrix_Free(inv);
429 Matrix_Free(T2);
432 /* Returns the power of (t+1) in the term of a rational generating function,
433 * i.e., the scalar product of the actual lattice point and lambda.
434 * The lattice point is the unique lattice point in the fundamental parallelepiped
435 * of the unimodual cone i shifted to the parametric vertex W/lcm.
437 * The rows of W refer to the coordinates of the vertex
438 * The first nparam columns are the coefficients of the parameters
439 * and the final column is the constant term.
440 * lcm is the common denominator of all coefficients.
442 * PD is the parameter domain, which, if != NULL, may be used to simply the
443 * resulting expression.
445 static evalue* lattice_point_fractional(const mat_ZZ& rays, vec_ZZ& lambda,
446 Matrix *V, Polyhedron *PD)
448 unsigned nparam = V->NbColumns-2;
450 Matrix* Rays = rays2matrix2(rays);
451 Matrix *T = Transpose(Rays);
452 Matrix *T2 = Matrix_Copy(T);
453 Matrix *inv = Matrix_Alloc(T2->NbRows, T2->NbColumns);
454 int ok = Matrix_Inverse(T2, inv);
455 assert(ok);
456 Matrix_Free(Rays);
457 Matrix_Free(T2);
458 mat_ZZ vertex;
459 matrix2zz(V, vertex, V->NbRows, V->NbColumns-1);
461 vec_ZZ num;
462 num = lambda * vertex;
464 evalue *EP = multi_monom(num);
466 evalue_div(EP, V->p[0][nparam+1]);
468 Matrix *L = Matrix_Alloc(inv->NbRows, V->NbColumns);
469 Matrix_Product(inv, V, L);
471 mat_ZZ RT;
472 matrix2zz(T, RT, T->NbRows, T->NbColumns);
473 Matrix_Free(T);
475 vec_ZZ p = lambda * RT;
477 for (int i = 0; i < L->NbRows; ++i) {
478 Vector_Oppose(L->p[i], L->p[i], nparam+1);
479 fractional_part(L->p[i], nparam+1, V->p[0][nparam+1], p[i], EP, PD);
482 Matrix_Free(L);
484 Matrix_Free(inv);
485 return EP;
488 static evalue* lattice_point(const mat_ZZ& rays, vec_ZZ& lambda,
489 Param_Vertices *V,
490 Polyhedron *PD, barvinok_options *options)
492 evalue *lp = lattice_point_fractional(rays, lambda, V->Vertex, PD);
493 if (options->lookup_table)
494 evalue_mod2table(lp, V->Vertex->NbColumns-2);
495 return lp;
498 /* returns the unique lattice point in the fundamental parallelepiped
499 * of the unimodual cone C shifted to the parametric vertex V.
501 * The return values num and E_vertex are such that
502 * coordinate i of this lattice point is equal to
504 * num[i] + E_vertex[i]
506 void lattice_point(Param_Vertices *V, const mat_ZZ& rays, vec_ZZ& num,
507 evalue **E_vertex, barvinok_options *options)
509 unsigned nparam = V->Vertex->NbColumns - 2;
510 unsigned dim = rays.NumCols();
511 vec_ZZ vertex;
512 vertex.SetLength(nparam+1);
514 Value lcm, tmp;
515 value_init(lcm);
516 value_init(tmp);
517 value_set_si(lcm, 1);
519 for (int j = 0; j < V->Vertex->NbRows; ++j) {
520 value_lcm(lcm, V->Vertex->p[j][nparam+1], &lcm);
523 if (value_notone_p(lcm)) {
524 Matrix * mv = Matrix_Alloc(dim, nparam+1);
525 for (int j = 0 ; j < dim; ++j) {
526 value_division(tmp, lcm, V->Vertex->p[j][nparam+1]);
527 Vector_Scale(V->Vertex->p[j], mv->p[j], tmp, nparam+1);
530 Matrix* Rays = rays2matrix2(rays);
531 Matrix *T = Transpose(Rays);
532 Matrix *T2 = Matrix_Copy(T);
533 Matrix *inv = Matrix_Alloc(T2->NbRows, T2->NbColumns);
534 int ok = Matrix_Inverse(T2, inv);
535 assert(ok);
536 Matrix_Free(Rays);
537 Matrix_Free(T2);
538 Matrix *L = Matrix_Alloc(inv->NbRows, mv->NbColumns);
539 Matrix_Product(inv, mv, L);
540 Matrix_Free(inv);
542 evalue f;
543 value_init(f.d);
544 value_init(f.x.n);
546 ZZ one;
548 evalue *remainders[dim];
549 for (int i = 0; i < dim; ++i) {
550 remainders[i] = evalue_zero();
551 one = 1;
552 ceil(L->p[i], nparam+1, lcm, one, remainders[i], 0, options);
554 Matrix_Free(L);
557 for (int i = 0; i < V->Vertex->NbRows; ++i) {
558 values2zz(mv->p[i], vertex, nparam+1);
559 E_vertex[i] = multi_monom(vertex);
560 num[i] = 0;
562 value_set_si(f.x.n, 1);
563 value_assign(f.d, lcm);
565 emul(&f, E_vertex[i]);
567 for (int j = 0; j < dim; ++j) {
568 if (value_zero_p(T->p[i][j]))
569 continue;
570 evalue cp;
571 value_init(cp.d);
572 evalue_copy(&cp, remainders[j]);
573 if (value_notone_p(T->p[i][j])) {
574 value_set_si(f.d, 1);
575 value_assign(f.x.n, T->p[i][j]);
576 emul(&f, &cp);
578 eadd(&cp, E_vertex[i]);
579 free_evalue_refs(&cp);
582 for (int i = 0; i < dim; ++i) {
583 free_evalue_refs(remainders[i]);
584 free(remainders[i]);
587 free_evalue_refs(&f);
589 Matrix_Free(T);
590 Matrix_Free(mv);
591 value_clear(lcm);
592 value_clear(tmp);
593 return;
595 value_clear(lcm);
596 value_clear(tmp);
598 for (int i = 0; i < V->Vertex->NbRows; ++i) {
599 /* fixed value */
600 if (First_Non_Zero(V->Vertex->p[i], nparam) == -1) {
601 E_vertex[i] = 0;
602 value2zz(V->Vertex->p[i][nparam], num[i]);
603 } else {
604 values2zz(V->Vertex->p[i], vertex, nparam+1);
605 E_vertex[i] = multi_monom(vertex);
606 num[i] = 0;
611 /* Returns the power of (t+1) in the term of a rational generating function,
612 * i.e., the scalar product of the actual lattice point and lambda.
613 * The lattice point is the unique lattice point in the fundamental parallelepiped
614 * of the unimodual cone i shifted to the parametric vertex V.
616 * PD is the parameter domain, which, if != NULL, may be used to simply the
617 * resulting expression.
619 * The result is returned in term.
621 void lattice_point(Param_Vertices* V, const mat_ZZ& rays, vec_ZZ& lambda,
622 term_info* term, Polyhedron *PD, barvinok_options *options)
624 unsigned nparam = V->Vertex->NbColumns - 2;
625 unsigned dim = rays.NumCols();
626 mat_ZZ vertex;
627 vertex.SetDims(V->Vertex->NbRows, nparam+1);
629 Param_Vertex_Common_Denominator(V);
630 if (value_notone_p(V->Vertex->p[0][nparam+1])) {
631 term->E = lattice_point(rays, lambda, V, PD, options);
632 term->constant = 0;
633 return;
635 for (int i = 0; i < V->Vertex->NbRows; ++i) {
636 assert(value_one_p(V->Vertex->p[i][nparam+1])); // for now
637 values2zz(V->Vertex->p[i], vertex[i], nparam+1);
640 vec_ZZ num;
641 num = lambda * vertex;
643 int nn = 0;
644 for (int j = 0; j < nparam; ++j)
645 if (num[j] != 0)
646 ++nn;
647 if (nn >= 1) {
648 term->E = multi_monom(num);
649 term->constant = 0;
650 } else {
651 term->E = NULL;
652 term->constant = num[nparam];