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"
11 #define ALLOC(type) (type*)malloc(sizeof(type))
13 /* returns an evalue that corresponds to
17 static evalue
*term(int param
, ZZ
& c
, Value
*den
= NULL
)
19 evalue
*EP
= new evalue();
21 value_set_si(EP
->d
,0);
22 EP
->x
.p
= new_enode(polynomial
, 2, param
+ 1);
23 evalue_set_si(&EP
->x
.p
->arr
[0], 0, 1);
24 value_init(EP
->x
.p
->arr
[1].x
.n
);
26 value_set_si(EP
->x
.p
->arr
[1].d
, 1);
28 value_assign(EP
->x
.p
->arr
[1].d
, *den
);
29 zz2value(c
, EP
->x
.p
->arr
[1].x
.n
);
33 /* returns an evalue that corresponds to
37 evalue
*multi_monom(vec_ZZ
& p
)
39 evalue
*X
= new evalue();
42 unsigned nparam
= p
.length()-1;
43 zz2value(p
[nparam
], X
->x
.n
);
44 value_set_si(X
->d
, 1);
45 for (int i
= 0; i
< nparam
; ++i
) {
48 evalue
*T
= term(i
, p
[i
]);
57 * Check whether mapping polyhedron P on the affine combination
58 * num yields a range that has a fixed quotient on integer
60 * If zero is true, then we are only interested in the quotient
61 * for the cases where the remainder is zero.
62 * Returns NULL if false and a newly allocated value if true.
64 static Value
*fixed_quotient(Polyhedron
*P
, vec_ZZ
& num
, Value d
, bool zero
)
67 int len
= num
.length();
68 Matrix
*T
= Matrix_Alloc(2, len
);
69 zz2values(num
, T
->p
[0]);
70 value_set_si(T
->p
[1][len
-1], 1);
71 Polyhedron
*I
= Polyhedron_Image(P
, T
, P
->NbConstraints
);
75 for (i
= 0; i
< I
->NbRays
; ++i
)
76 if (value_zero_p(I
->Ray
[i
][2])) {
84 int bounded
= line_minmax(I
, &min
, &max
);
88 mpz_cdiv_q(min
, min
, d
);
90 mpz_fdiv_q(min
, min
, d
);
91 mpz_fdiv_q(max
, max
, d
);
93 if (value_eq(min
, max
)) {
96 value_assign(*ret
, min
);
104 * Normalize linear expression coef modulo m
105 * Removes common factor and reduces coefficients
106 * Returns index of first non-zero coefficient or len
108 int normal_mod(Value
*coef
, int len
, Value
*m
)
113 Vector_Gcd(coef
, len
, &gcd
);
115 Vector_AntiScale(coef
, coef
, gcd
, len
);
117 value_division(*m
, *m
, gcd
);
124 for (j
= 0; j
< len
; ++j
)
125 mpz_fdiv_r(coef
[j
], coef
[j
], *m
);
126 for (j
= 0; j
< len
; ++j
)
127 if (value_notzero_p(coef
[j
]))
133 static bool mod_needed(Polyhedron
*PD
, vec_ZZ
& num
, Value d
, evalue
*E
)
135 Value
*q
= fixed_quotient(PD
, num
, d
, false);
140 value_oppose(*q
, *q
);
143 value_set_si(EV
.d
, 1);
145 value_multiply(EV
.x
.n
, *q
, d
);
147 free_evalue_refs(&EV
);
153 /* modifies f argument ! */
154 static void ceil_mod(Value
*coef
, int len
, Value d
, ZZ
& f
, evalue
*EP
, Polyhedron
*PD
)
160 Vector_Scale(coef
, coef
, m
, len
);
163 int j
= normal_mod(coef
, len
, &m
);
171 values2zz(coef
, num
, len
);
178 evalue_set_si(&tmp
, 0, 1);
182 while (j
< len
-1 && (num
[j
] == g
/2 || num
[j
] == 0))
184 if ((j
< len
-1 && num
[j
] > g
/2) || (j
== len
-1 && num
[j
] >= (g
+1)/2)) {
185 for (int k
= j
; k
< len
-1; ++k
)
188 num
[len
-1] = g
- 1 - num
[len
-1];
189 value_assign(tmp
.d
, m
);
191 zz2value(t
, tmp
.x
.n
);
197 ZZ t
= num
[len
-1] * f
;
198 zz2value(t
, tmp
.x
.n
);
199 value_assign(tmp
.d
, m
);
202 evalue
*E
= multi_monom(num
);
206 if (PD
&& !mod_needed(PD
, num
, m
, E
)) {
209 value_assign(EV
.d
, m
);
214 value_set_si(EV
.x
.n
, 1);
215 value_assign(EV
.d
, m
);
218 value_set_si(EV
.d
, 0);
219 EV
.x
.p
= new_enode(fractional
, 3, -1);
220 evalue_copy(&EV
.x
.p
->arr
[0], E
);
221 evalue_set_si(&EV
.x
.p
->arr
[1], 0, 1);
222 value_init(EV
.x
.p
->arr
[2].x
.n
);
223 zz2value(f
, EV
.x
.p
->arr
[2].x
.n
);
224 value_set_si(EV
.x
.p
->arr
[2].d
, 1);
229 free_evalue_refs(&EV
);
234 free_evalue_refs(&tmp
);
241 static void ceil(Value
*coef
, int len
, Value d
, ZZ
& f
,
242 evalue
*EP
, Polyhedron
*PD
) {
243 ceil_mod(coef
, len
, d
, f
, EP
, PD
);
246 static void ceil(Value
*coef
, int len
, Value d
, ZZ
& f
,
247 evalue
*EP
, Polyhedron
*PD
) {
248 ceil_mod(coef
, len
, d
, f
, EP
, PD
);
249 evalue_mod2table(EP
, len
-1);
253 evalue
* bv_ceil3(Value
*coef
, int len
, Value d
, Polyhedron
*P
)
255 Vector
*val
= Vector_Alloc(len
);
260 Vector_Scale(coef
, val
->p
, t
, len
);
261 value_absolute(t
, d
);
264 values2zz(val
->p
, num
, len
);
265 evalue
*EP
= multi_monom(num
);
270 value_set_si(tmp
.x
.n
, 1);
271 value_assign(tmp
.d
, t
);
277 ceil_mod(val
->p
, len
, t
, one
, EP
, P
);
280 /* copy EP to malloc'ed evalue */
281 evalue
*E
= ALLOC(evalue
);
285 free_evalue_refs(&tmp
);
291 void lattice_point(Value
* values
, Polyhedron
*i
, vec_ZZ
& vertex
)
293 unsigned dim
= i
->Dimension
;
294 if(!value_one_p(values
[dim
])) {
295 Matrix
* Rays
= rays(i
);
296 Matrix
*inv
= Matrix_Alloc(Rays
->NbRows
, Rays
->NbColumns
);
297 int ok
= Matrix_Inverse(Rays
, inv
);
301 Vector
*lambda
= Vector_Alloc(dim
+1);
302 Vector_Matrix_Product(values
, inv
, lambda
->p
);
304 for (int j
= 0; j
< dim
; ++j
)
305 mpz_cdiv_q(lambda
->p
[j
], lambda
->p
[j
], lambda
->p
[dim
]);
306 value_set_si(lambda
->p
[dim
], 1);
307 Vector
*A
= Vector_Alloc(dim
+1);
308 Vector_Matrix_Product(lambda
->p
, Rays
, A
->p
);
311 values2zz(A
->p
, vertex
, dim
);
314 values2zz(values
, vertex
, dim
);
317 static void vertex_period(
318 Polyhedron
*i
, vec_ZZ
& lambda
, Matrix
*T
,
319 Value lcm
, int p
, Vector
*val
,
320 evalue
*E
, evalue
* ev
,
323 unsigned nparam
= T
->NbRows
- 1;
324 unsigned dim
= i
->Dimension
;
331 Vector
* values
= Vector_Alloc(dim
+ 1);
332 Vector_Matrix_Product(val
->p
, T
, values
->p
);
333 value_assign(values
->p
[dim
], lcm
);
334 lattice_point(values
->p
, i
, vertex
);
335 num
= vertex
* lambda
;
340 zz2value(num
, ev
->x
.n
);
341 value_assign(ev
->d
, lcm
);
348 values2zz(T
->p
[p
], vertex
, dim
);
349 nump
= vertex
* lambda
;
350 if (First_Non_Zero(val
->p
, p
) == -1) {
351 value_assign(tmp
, lcm
);
352 evalue
*ET
= term(p
, nump
, &tmp
);
354 free_evalue_refs(ET
);
358 value_assign(tmp
, lcm
);
359 if (First_Non_Zero(T
->p
[p
], dim
) != -1)
360 Vector_Gcd(T
->p
[p
], dim
, &tmp
);
362 if (value_lt(tmp
, lcm
)) {
365 value_division(tmp
, lcm
, tmp
);
366 value_set_si(ev
->d
, 0);
367 ev
->x
.p
= new_enode(periodic
, VALUE_TO_INT(tmp
), p
+1);
368 value2zz(tmp
, count
);
370 value_decrement(tmp
, tmp
);
372 ZZ new_offset
= offset
- count
* nump
;
373 value_assign(val
->p
[p
], tmp
);
374 vertex_period(i
, lambda
, T
, lcm
, p
+1, val
, E
,
375 &ev
->x
.p
->arr
[VALUE_TO_INT(tmp
)], new_offset
);
376 } while (value_pos_p(tmp
));
378 vertex_period(i
, lambda
, T
, lcm
, p
+1, val
, E
, ev
, offset
);
382 /* Returns the power of (t+1) in the term of a rational generating function,
383 * i.e., the scalar product of the actual lattice point and lambda.
384 * The lattice point is the unique lattice point in the fundamental parallelepiped
385 * of the unimodual cone i shifted to the parametric vertex W/lcm.
387 * The rows of W refer to the coordinates of the vertex
388 * The first nparam columns are the coefficients of the parameters
389 * and the final column is the constant term.
390 * lcm is the common denominator of all coefficients.
392 * PD is the parameter domain, which, if != NULL, may be used to simply the
393 * resulting expression.
396 evalue
* lattice_point(
397 Polyhedron
*i
, vec_ZZ
& lambda
, Matrix
*W
, Value lcm
, Polyhedron
*PD
)
399 unsigned nparam
= W
->NbColumns
- 1;
401 Matrix
* Rays
= rays2(i
);
402 Matrix
*T
= Transpose(Rays
);
403 Matrix
*T2
= Matrix_Copy(T
);
404 Matrix
*inv
= Matrix_Alloc(T2
->NbRows
, T2
->NbColumns
);
405 int ok
= Matrix_Inverse(T2
, inv
);
410 matrix2zz(W
, vertex
, W
->NbRows
, W
->NbColumns
);
413 num
= lambda
* vertex
;
415 evalue
*EP
= multi_monom(num
);
420 value_set_si(tmp
.x
.n
, 1);
421 value_assign(tmp
.d
, lcm
);
425 Matrix
*L
= Matrix_Alloc(inv
->NbRows
, W
->NbColumns
);
426 Matrix_Product(inv
, W
, L
);
429 matrix2zz(T
, RT
, T
->NbRows
, T
->NbColumns
);
432 vec_ZZ p
= lambda
* RT
;
434 for (int i
= 0; i
< L
->NbRows
; ++i
) {
435 ceil_mod(L
->p
[i
], nparam
+1, lcm
, p
[i
], EP
, PD
);
441 free_evalue_refs(&tmp
);
445 evalue
* lattice_point(
446 Polyhedron
*i
, vec_ZZ
& lambda
, Matrix
*W
, Value lcm
, Polyhedron
*PD
)
448 Matrix
*T
= Transpose(W
);
449 unsigned nparam
= T
->NbRows
- 1;
451 evalue
*EP
= new evalue();
453 evalue_set_si(EP
, 0, 1);
456 Vector
*val
= Vector_Alloc(nparam
+1);
457 value_set_si(val
->p
[nparam
], 1);
458 ZZ
offset(INIT_VAL
, 0);
460 vertex_period(i
, lambda
, T
, lcm
, 0, val
, EP
, &ev
, offset
);
463 free_evalue_refs(&ev
);
473 /* returns the unique lattice point in the fundamental parallelepiped
474 * of the unimodual cone C shifted to the parametric vertex V.
476 * The return values num and E_vertex are such that
477 * coordinate i of this lattice point is equal to
479 * num[i] + E_vertex[i]
481 void lattice_point(Param_Vertices
*V
, Polyhedron
*C
, vec_ZZ
& num
,
484 unsigned nparam
= V
->Vertex
->NbColumns
- 2;
485 unsigned dim
= C
->Dimension
;
487 vertex
.SetLength(nparam
+1);
492 value_set_si(lcm
, 1);
494 for (int j
= 0; j
< V
->Vertex
->NbRows
; ++j
) {
495 value_lcm(lcm
, V
->Vertex
->p
[j
][nparam
+1], &lcm
);
498 if (value_notone_p(lcm
)) {
499 Matrix
* mv
= Matrix_Alloc(dim
, nparam
+1);
500 for (int j
= 0 ; j
< dim
; ++j
) {
501 value_division(tmp
, lcm
, V
->Vertex
->p
[j
][nparam
+1]);
502 Vector_Scale(V
->Vertex
->p
[j
], mv
->p
[j
], tmp
, nparam
+1);
505 Matrix
* Rays
= rays2(C
);
506 Matrix
*T
= Transpose(Rays
);
507 Matrix
*T2
= Matrix_Copy(T
);
508 Matrix
*inv
= Matrix_Alloc(T2
->NbRows
, T2
->NbColumns
);
509 int ok
= Matrix_Inverse(T2
, inv
);
513 Matrix
*L
= Matrix_Alloc(inv
->NbRows
, mv
->NbColumns
);
514 Matrix_Product(inv
, mv
, L
);
523 evalue
*remainders
[dim
];
524 for (int i
= 0; i
< dim
; ++i
) {
525 remainders
[i
] = evalue_zero();
527 ceil(L
->p
[i
], nparam
+1, lcm
, one
, remainders
[i
], 0);
532 for (int i
= 0; i
< V
->Vertex
->NbRows
; ++i
) {
533 values2zz(mv
->p
[i
], vertex
, nparam
+1);
534 E_vertex
[i
] = multi_monom(vertex
);
537 value_set_si(f
.x
.n
, 1);
538 value_assign(f
.d
, lcm
);
540 emul(&f
, E_vertex
[i
]);
542 for (int j
= 0; j
< dim
; ++j
) {
543 if (value_zero_p(T
->p
[i
][j
]))
547 evalue_copy(&cp
, remainders
[j
]);
548 if (value_notone_p(T
->p
[i
][j
])) {
549 value_set_si(f
.d
, 1);
550 value_assign(f
.x
.n
, T
->p
[i
][j
]);
553 eadd(&cp
, E_vertex
[i
]);
554 free_evalue_refs(&cp
);
557 for (int i
= 0; i
< dim
; ++i
) {
558 free_evalue_refs(remainders
[i
]);
562 free_evalue_refs(&f
);
573 for (int i
= 0; i
< V
->Vertex
->NbRows
; ++i
) {
575 if (First_Non_Zero(V
->Vertex
->p
[i
], nparam
) == -1) {
577 value2zz(V
->Vertex
->p
[i
][nparam
], num
[i
]);
579 values2zz(V
->Vertex
->p
[i
], vertex
, nparam
+1);
580 E_vertex
[i
] = multi_monom(vertex
);