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>
8 #include "conversion.h"
9 #include "lattice_point.h"
10 #include "param_util.h"
15 #define ALLOC(type) (type*)malloc(sizeof(type))
17 /* returns an evalue that corresponds to
21 static evalue
*term(int param
, ZZ
& c
, Value
*den
= NULL
)
23 evalue
*EP
= new evalue();
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
);
30 value_set_si(EP
->x
.p
->arr
[1].d
, 1);
32 value_assign(EP
->x
.p
->arr
[1].d
, *den
);
33 zz2value(c
, EP
->x
.p
->arr
[1].x
.n
);
37 /* returns an evalue that corresponds to
41 evalue
*multi_monom(vec_ZZ
& p
)
43 evalue
*X
= new evalue();
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
) {
52 evalue
*T
= term(i
, p
[i
]);
61 * Check whether mapping polyhedron P on the affine combination
62 * num yields a range that has a fixed quotient on integer
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
)
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
);
79 for (i
= 0; i
< I
->NbRays
; ++i
)
80 if (value_zero_p(I
->Ray
[i
][2])) {
88 int bounded
= line_minmax(I
, &min
, &max
);
92 mpz_cdiv_q(min
, min
, d
);
94 mpz_fdiv_q(min
, min
, d
);
95 mpz_fdiv_q(max
, max
, d
);
97 if (value_eq(min
, max
)) {
100 value_assign(*ret
, min
);
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
)
117 Vector_Gcd(coef
, len
, &gcd
);
119 Vector_AntiScale(coef
, coef
, gcd
, len
);
121 value_division(*m
, *m
, gcd
);
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
]))
137 static bool mod_needed(Polyhedron
*PD
, vec_ZZ
& num
, Value d
, evalue
*E
)
139 Value
*q
= fixed_quotient(PD
, num
, d
, false);
144 value_oppose(*q
, *q
);
147 value_set_si(EV
.d
, 1);
149 value_multiply(EV
.x
.n
, *q
, d
);
151 free_evalue_refs(&EV
);
157 /* modifies coef argument ! */
158 static void fractional_part(Value
*coef
, int len
, Value d
, ZZ f
, evalue
*EP
,
159 Polyhedron
*PD
, bool up
)
165 /* f {{ x }} = f - f { -x } */
167 evalue_add_constant(EP
, m
);
168 Vector_Oppose(coef
, coef
, len
);
173 int j
= normal_mod(coef
, len
, &m
);
181 values2zz(coef
, num
, len
);
188 evalue_set_si(&tmp
, 0, 1);
192 while (j
< len
-1 && (num
[j
] == g
/2 || num
[j
] == 0))
194 if ((j
< len
-1 && num
[j
] > g
/2) || (j
== len
-1 && num
[j
] >= (g
+1)/2)) {
195 for (int k
= j
; k
< len
-1; ++k
)
198 num
[len
-1] = g
- 1 - num
[len
-1];
199 value_assign(tmp
.d
, m
);
201 zz2value(t
, tmp
.x
.n
);
207 ZZ t
= num
[len
-1] * f
;
208 zz2value(t
, tmp
.x
.n
);
209 value_assign(tmp
.d
, m
);
212 evalue
*E
= multi_monom(num
);
216 if (PD
&& !mod_needed(PD
, num
, m
, E
)) {
219 value_assign(EV
.d
, m
);
224 value_set_si(EV
.x
.n
, 1);
225 value_assign(EV
.d
, m
);
228 value_set_si(EV
.d
, 0);
229 EV
.x
.p
= new_enode(fractional
, 3, -1);
230 evalue_copy(&EV
.x
.p
->arr
[0], E
);
231 evalue_set_si(&EV
.x
.p
->arr
[1], 0, 1);
232 value_init(EV
.x
.p
->arr
[2].x
.n
);
233 zz2value(f
, EV
.x
.p
->arr
[2].x
.n
);
234 value_set_si(EV
.x
.p
->arr
[2].d
, 1);
239 free_evalue_refs(&EV
);
244 free_evalue_refs(&tmp
);
250 static void ceil(Value
*coef
, int len
, Value d
, ZZ
& f
,
251 evalue
*EP
, barvinok_options
*options
)
253 Vector_Oppose(coef
, coef
, len
);
254 fractional_part(coef
, len
, d
, f
, EP
, NULL
, false);
255 if (options
->lookup_table
)
256 evalue_mod2table(EP
, len
-1);
259 evalue
* bv_ceil3(Value
*coef
, int len
, Value d
, Polyhedron
*P
)
261 Vector
*val
= Vector_Alloc(len
);
266 Vector_Scale(coef
, val
->p
, t
, len
);
267 value_absolute(t
, d
);
270 values2zz(val
->p
, num
, len
);
271 evalue
*EP
= multi_monom(num
);
276 value_set_si(tmp
.x
.n
, 1);
277 value_assign(tmp
.d
, t
);
283 Vector_Oppose(val
->p
, val
->p
, len
);
284 fractional_part(val
->p
, len
, t
, one
, EP
, P
, false);
287 /* copy EP to malloc'ed evalue */
288 evalue
*E
= ALLOC(evalue
);
292 free_evalue_refs(&tmp
);
298 void lattice_point_fixed(Value
*vertex
, Value
*vertex_res
,
299 Matrix
*Rays
, Matrix
*Rays_res
,
300 Value
*point
, int *closed
)
302 unsigned dim
= Rays
->NbRows
;
303 if (value_one_p(vertex
[dim
]) && !closed
)
304 Vector_Copy(vertex_res
, point
, Rays_res
->NbColumns
);
306 Matrix
*R2
= Matrix_Copy(Rays
);
307 Matrix
*inv
= Matrix_Alloc(Rays
->NbRows
, Rays
->NbColumns
);
308 int ok
= Matrix_Inverse(R2
, inv
);
311 Vector
*lambda
= Vector_Alloc(dim
);
312 Vector_Matrix_Product(vertex
, inv
, lambda
->p
);
314 for (int j
= 0; j
< dim
; ++j
)
315 if (!closed
|| closed
[j
])
316 mpz_cdiv_q(lambda
->p
[j
], lambda
->p
[j
], vertex
[dim
]);
318 value_addto(lambda
->p
[j
], lambda
->p
[j
], vertex
[dim
]);
319 mpz_fdiv_q(lambda
->p
[j
], lambda
->p
[j
], vertex
[dim
]);
321 Vector_Matrix_Product(lambda
->p
, Rays_res
, point
);
326 static Matrix
*Matrix_AddRowColumn(Matrix
*M
)
328 Matrix
*M2
= Matrix_Alloc(M
->NbRows
+1, M
->NbColumns
+1);
329 for (int i
= 0; i
< M
->NbRows
; ++i
)
330 Vector_Copy(M
->p
[i
], M2
->p
[i
], M
->NbColumns
);
331 value_set_si(M2
->p
[M
->NbRows
][M
->NbColumns
], 1);
335 #define FORALL_COSETS(det,D,i,k) \
337 Vector *k = Vector_Alloc(D->NbRows+1); \
338 value_set_si(k->p[D->NbRows], 1); \
339 for (unsigned long i = 0; i < det; ++i) { \
340 unsigned long _fc_val = i; \
341 for (int j = 0; j < D->NbRows; ++j) { \
342 value_set_si(k->p[j], _fc_val % mpz_get_ui(D->p[j][j]));\
343 _fc_val /= mpz_get_ui(D->p[j][j]); \
345 #define END_FORALL_COSETS \
350 /* Compute the lattice points in the vertex cone at "values" with rays "rays".
351 * The lattice points are returned in "vertex".
353 * Rays has the generators as rows and so does W.
354 * We first compute { m-v, u_i^* } with m = k W, where k runs through
357 * [k 1] [ d1*W 0 ] [ U' 0 ] = [k 1] T2
359 * where d1 and d2 are the denominators of v and U^{-1}=U'/d2.
360 * Then lambda = { k } (componentwise)
361 * We compute x - floor(x) = {x} = { a/b } as fdiv_r(a,b)/b
362 * For open rays/facets, we need values in (0,1] rather than [0,1),
363 * so we compute {{x}} = x - ceil(x-1) = a/b - ceil((a-b)/b)
364 * = (a - b cdiv_q(a-b,b) - b + b)/b
365 * = (cdiv_r(a,b)+b)/b
366 * Finally, we compute v + lambda * U
367 * The denominator of lambda can be d1*d2, that of lambda2 = lambda*U
368 * can be at most d1, since it is integer if v = 0.
369 * The denominator of v + lambda2 is 1.
371 * The _res variants of the input variables may have been multiplied with
372 * a (list of) nonorthogonal vector(s) and may therefore have fewer columns
373 * than their original counterparts.
375 void lattice_points_fixed(Value
*vertex
, Value
*vertex_res
,
376 Matrix
*Rays
, Matrix
*Rays_res
, Matrix
*points
,
377 unsigned long det
, int *closed
)
379 unsigned dim
= Rays
->NbRows
;
381 lattice_point_fixed(vertex
, vertex_res
, Rays
, Rays_res
,
382 points
->p
[0], closed
);
386 Smith(Rays
, &U
, &W
, &D
);
390 unsigned long det2
= 1;
391 for (int i
= 0 ; i
< D
->NbRows
; ++i
)
392 det2
*= mpz_get_ui(D
->p
[i
][i
]);
395 Matrix
*T
= Matrix_Alloc(W
->NbRows
+1, W
->NbColumns
+1);
396 for (int i
= 0; i
< W
->NbRows
; ++i
)
397 Vector_Scale(W
->p
[i
], T
->p
[i
], vertex
[dim
], W
->NbColumns
);
401 value_set_si(tmp
, -1);
402 Vector_Scale(vertex
, T
->p
[dim
], tmp
, dim
);
404 value_assign(T
->p
[dim
][dim
], vertex
[dim
]);
406 Matrix
*R2
= Matrix_AddRowColumn(Rays
);
407 Matrix
*inv
= Matrix_Alloc(R2
->NbRows
, R2
->NbColumns
);
408 int ok
= Matrix_Inverse(R2
, inv
);
412 Matrix
*T2
= Matrix_Alloc(dim
+1, dim
+1);
413 Matrix_Product(T
, inv
, T2
);
416 Vector
*lambda
= Vector_Alloc(dim
+1);
417 Vector
*lambda2
= Vector_Alloc(Rays_res
->NbColumns
);
418 FORALL_COSETS(det
, D
, i
, k
)
419 Vector_Matrix_Product(k
->p
, T2
, lambda
->p
);
420 for (int j
= 0; j
< dim
; ++j
)
421 if (!closed
|| closed
[j
])
422 mpz_fdiv_r(lambda
->p
[j
], lambda
->p
[j
], lambda
->p
[dim
]);
424 mpz_cdiv_r(lambda
->p
[j
], lambda
->p
[j
], lambda
->p
[dim
]);
425 value_addto(lambda
->p
[j
], lambda
->p
[j
], lambda
->p
[dim
]);
427 Vector_Matrix_Product(lambda
->p
, Rays_res
, lambda2
->p
);
428 for (int j
= 0; j
< lambda2
->Size
; ++j
)
429 assert(mpz_divisible_p(lambda2
->p
[j
], inv
->p
[dim
][dim
]));
430 Vector_AntiScale(lambda2
->p
, lambda2
->p
, inv
->p
[dim
][dim
], lambda2
->Size
);
431 Vector_Add(lambda2
->p
, vertex_res
, lambda2
->p
, lambda2
->Size
);
432 for (int j
= 0; j
< lambda2
->Size
; ++j
)
433 assert(mpz_divisible_p(lambda2
->p
[j
], vertex
[dim
]));
434 Vector_AntiScale(lambda2
->p
, points
->p
[i
], vertex
[dim
], lambda2
->Size
);
437 Vector_Free(lambda2
);
444 /* Returns the power of (t+1) in the term of a rational generating function,
445 * i.e., the scalar product of the actual lattice point and lambda.
446 * The lattice point is the unique lattice point in the fundamental parallelepiped
447 * of the unimodual cone i shifted to the parametric vertex W/lcm.
449 * The rows of W refer to the coordinates of the vertex
450 * The first nparam columns are the coefficients of the parameters
451 * and the final column is the constant term.
452 * lcm is the common denominator of all coefficients.
454 static evalue
**lattice_point_fractional(const mat_ZZ
& rays
, vec_ZZ
& lambda
,
456 unsigned long det
, int *closed
)
458 unsigned nparam
= V
->NbColumns
-2;
459 evalue
**E
= new evalue
*[det
];
461 Matrix
* Rays
= zz2matrix(rays
);
462 Matrix
*T
= Transpose(Rays
);
463 Matrix
*T2
= Matrix_Copy(T
);
464 Matrix
*inv
= Matrix_Alloc(T2
->NbRows
, T2
->NbColumns
);
465 int ok
= Matrix_Inverse(T2
, inv
);
469 matrix2zz(V
, vertex
, V
->NbRows
, V
->NbColumns
-1);
472 num
= lambda
* vertex
;
474 evalue
*EP
= multi_monom(num
);
476 evalue_div(EP
, V
->p
[0][nparam
+1]);
478 Matrix
*L
= Matrix_Alloc(inv
->NbRows
, V
->NbColumns
);
479 Matrix_Product(inv
, V
, L
);
482 matrix2zz(T
, RT
, T
->NbRows
, T
->NbColumns
);
485 vec_ZZ p
= lambda
* RT
;
488 for (int i
= 0; i
< L
->NbRows
; ++i
) {
489 Vector_Oppose(L
->p
[i
], L
->p
[i
], nparam
+1);
490 fractional_part(L
->p
[i
], nparam
+1, V
->p
[i
][nparam
+1], p
[i
],
491 EP
, NULL
, closed
&& !closed
[i
]);
495 for (int i
= 0; i
< L
->NbRows
; ++i
)
496 value_assign(L
->p
[i
][nparam
+1], V
->p
[i
][nparam
+1]);
500 mpz_set_ui(denom
, det
);
501 value_multiply(denom
, L
->p
[0][nparam
+1], denom
);
504 Smith(Rays
, &U
, &W
, &D
);
508 unsigned long det2
= 1;
509 for (int i
= 0 ; i
< D
->NbRows
; ++i
)
510 det2
*= mpz_get_ui(D
->p
[i
][i
]);
513 Matrix_Transposition(inv
);
514 Matrix
*T2
= Matrix_Alloc(W
->NbRows
, inv
->NbColumns
);
515 Matrix_Product(W
, inv
, T2
);
518 unsigned dim
= D
->NbRows
;
519 Vector
*lambda
= Vector_Alloc(dim
);
521 Vector
*row
= Vector_Alloc(nparam
+1);
522 FORALL_COSETS(det
, D
, i
, k
)
523 Vector_Matrix_Product(k
->p
, T2
, lambda
->p
);
526 evalue_copy(E
[i
], EP
);
527 for (int j
= 0; j
< L
->NbRows
; ++j
) {
528 Vector_Oppose(L
->p
[j
], row
->p
, nparam
+1);
529 value_addmul(row
->p
[nparam
], L
->p
[j
][nparam
+1], lambda
->p
[j
]);
530 fractional_part(row
->p
, nparam
+1, denom
, p
[j
],
531 E
[i
], NULL
, closed
&& !closed
[j
]);
541 free_evalue_refs(EP
);
552 static evalue
**lattice_point(const mat_ZZ
& rays
, vec_ZZ
& lambda
,
554 unsigned long det
, int *closed
,
555 barvinok_options
*options
)
557 evalue
**lp
= lattice_point_fractional(rays
, lambda
, V
->Vertex
, det
, closed
);
558 if (options
->lookup_table
) {
559 for (int i
= 0; i
< det
; ++i
)
560 evalue_mod2table(lp
[i
], V
->Vertex
->NbColumns
-2);
565 /* returns the unique lattice point in the fundamental parallelepiped
566 * of the unimodual cone C shifted to the parametric vertex V.
568 * The return values num and E_vertex are such that
569 * coordinate i of this lattice point is equal to
571 * num[i] + E_vertex[i]
573 void lattice_point(Param_Vertices
*V
, const mat_ZZ
& rays
, vec_ZZ
& num
,
574 evalue
**E_vertex
, barvinok_options
*options
)
576 unsigned nparam
= V
->Vertex
->NbColumns
- 2;
577 unsigned dim
= rays
.NumCols();
579 vertex
.SetLength(nparam
+1);
584 value_set_si(lcm
, 1);
586 for (int j
= 0; j
< V
->Vertex
->NbRows
; ++j
) {
587 value_lcm(lcm
, V
->Vertex
->p
[j
][nparam
+1], &lcm
);
590 if (value_notone_p(lcm
)) {
591 Matrix
* mv
= Matrix_Alloc(dim
, nparam
+1);
592 for (int j
= 0 ; j
< dim
; ++j
) {
593 value_division(tmp
, lcm
, V
->Vertex
->p
[j
][nparam
+1]);
594 Vector_Scale(V
->Vertex
->p
[j
], mv
->p
[j
], tmp
, nparam
+1);
597 Matrix
* Rays
= zz2matrix(rays
);
598 Matrix
*T
= Transpose(Rays
);
599 Matrix
*T2
= Matrix_Copy(T
);
600 Matrix
*inv
= Matrix_Alloc(T2
->NbRows
, T2
->NbColumns
);
601 int ok
= Matrix_Inverse(T2
, inv
);
605 Matrix
*L
= Matrix_Alloc(inv
->NbRows
, mv
->NbColumns
);
606 Matrix_Product(inv
, mv
, L
);
615 evalue
*remainders
[dim
];
616 for (int i
= 0; i
< dim
; ++i
) {
617 remainders
[i
] = evalue_zero();
619 ceil(L
->p
[i
], nparam
+1, lcm
, one
, remainders
[i
], options
);
624 for (int i
= 0; i
< V
->Vertex
->NbRows
; ++i
) {
625 values2zz(mv
->p
[i
], vertex
, nparam
+1);
626 E_vertex
[i
] = multi_monom(vertex
);
629 value_set_si(f
.x
.n
, 1);
630 value_assign(f
.d
, lcm
);
632 emul(&f
, E_vertex
[i
]);
634 for (int j
= 0; j
< dim
; ++j
) {
635 if (value_zero_p(T
->p
[i
][j
]))
639 evalue_copy(&cp
, remainders
[j
]);
640 if (value_notone_p(T
->p
[i
][j
])) {
641 value_set_si(f
.d
, 1);
642 value_assign(f
.x
.n
, T
->p
[i
][j
]);
645 eadd(&cp
, E_vertex
[i
]);
646 free_evalue_refs(&cp
);
649 for (int i
= 0; i
< dim
; ++i
) {
650 free_evalue_refs(remainders
[i
]);
654 free_evalue_refs(&f
);
665 for (int i
= 0; i
< V
->Vertex
->NbRows
; ++i
) {
667 if (First_Non_Zero(V
->Vertex
->p
[i
], nparam
) == -1) {
669 value2zz(V
->Vertex
->p
[i
][nparam
], num
[i
]);
671 values2zz(V
->Vertex
->p
[i
], vertex
, nparam
+1);
672 E_vertex
[i
] = multi_monom(vertex
);
678 static int lattice_point_fixed(Param_Vertices
* V
, const mat_ZZ
& rays
,
679 vec_ZZ
& lambda
, term_info
* term
, unsigned long det
, int *closed
)
681 unsigned nparam
= V
->Vertex
->NbColumns
- 2;
682 unsigned dim
= rays
.NumCols();
684 for (int i
= 0; i
< dim
; ++i
)
685 if (First_Non_Zero(V
->Vertex
->p
[i
], nparam
) != -1)
688 Vector
*fixed
= Vector_Alloc(dim
+1);
689 for (int i
= 0; i
< dim
; ++i
)
690 value_assign(fixed
->p
[i
], V
->Vertex
->p
[i
][nparam
]);
691 value_assign(fixed
->p
[dim
], V
->Vertex
->p
[0][nparam
+1]);
694 Matrix
*points
= Matrix_Alloc(det
, dim
);
695 Matrix
* Rays
= zz2matrix(rays
);
696 lattice_points_fixed(fixed
->p
, fixed
->p
, Rays
, Rays
, points
, det
, closed
);
698 matrix2zz(points
, vertex
, points
->NbRows
, points
->NbColumns
);
701 term
->constant
= vertex
* lambda
;
707 /* Returns the power of (t+1) in the term of a rational generating function,
708 * i.e., the scalar product of the actual lattice point and lambda.
709 * The lattice point is the unique lattice point in the fundamental parallelepiped
710 * of the unimodual cone i shifted to the parametric vertex V.
712 * The result is returned in term.
714 void lattice_point(Param_Vertices
* V
, const mat_ZZ
& rays
, vec_ZZ
& lambda
,
715 term_info
* term
, unsigned long det
, int *closed
,
716 barvinok_options
*options
)
718 unsigned nparam
= V
->Vertex
->NbColumns
- 2;
719 unsigned dim
= rays
.NumCols();
721 vertex
.SetDims(V
->Vertex
->NbRows
, nparam
+1);
723 Param_Vertex_Common_Denominator(V
);
725 if (lattice_point_fixed(V
, rays
, lambda
, term
, det
, closed
))
728 if (det
!= 1 || closed
|| value_notone_p(V
->Vertex
->p
[0][nparam
+1])) {
729 term
->E
= lattice_point(rays
, lambda
, V
, det
, closed
, options
);
732 for (int i
= 0; i
< V
->Vertex
->NbRows
; ++i
) {
733 assert(value_one_p(V
->Vertex
->p
[i
][nparam
+1])); // for now
734 values2zz(V
->Vertex
->p
[i
], vertex
[i
], nparam
+1);
738 num
= lambda
* vertex
;
741 for (int j
= 0; j
< nparam
; ++j
)
745 term
->E
= new evalue
*[1];
746 term
->E
[0] = multi_monom(num
);
749 term
->constant
.SetLength(1);
750 term
->constant
[0] = num
[nparam
];