1 #include <barvinok/util.h>
2 #include <barvinok/options.h>
5 /* If a vertex is described by A x + B p + c = 0, then
6 * M = [A B] and we want to compute a linear transformation L such
7 * that H L = A and H \Z contains both A \Z and B \Z.
9 * [ A B ] = [ H 0 ] [ U_11 U_12 ]
12 * U_11 is the required linear transformation.
13 * Note that this also works if M has more rows than there are variables,
14 * i.e., if some rows in M are linear combinations of other rows.
15 * These extra rows only affect and H and not U.
17 static Lattice
*extract_lattice(Matrix
*M
, unsigned nvar
)
20 Matrix
*H
, *Q
, *U
, *Li
;
24 left_hermite(M
, &H
, &Q
, &U
);
27 Li
= Matrix_Alloc(nvar
+1, nvar
+1);
28 L
= Matrix_Alloc(nvar
+1, nvar
+1);
29 value_set_si(Li
->p
[nvar
][nvar
], 1);
31 for (row
= 0; row
< nvar
; ++row
)
32 Vector_Copy(Q
->p
[row
], Li
->p
[row
], nvar
);
36 ok
= Matrix_Inverse(Li
, L
);
43 /* Returns the smallest (wrt inclusion) lattice that contains both X and Y */
44 static Lattice
*LatticeJoin(Lattice
*X
, Lattice
*Y
)
47 int dim
= X
->NbRows
-1;
51 Matrix
*M
, *H
, *U
, *Q
;
53 assert(X
->NbColumns
-1 == dim
);
54 assert(Y
->NbRows
-1 == dim
);
55 assert(Y
->NbColumns
-1 == dim
);
60 M
= Matrix_Alloc(dim
, 2*dim
);
61 value_lcm(X
->p
[dim
][dim
], Y
->p
[dim
][dim
], &lcm
);
63 value_division(tmp
, lcm
, X
->p
[dim
][dim
]);
64 for (i
= 0; i
< dim
; ++i
)
65 Vector_Scale(X
->p
[i
], M
->p
[i
], tmp
, dim
);
66 value_division(tmp
, lcm
, Y
->p
[dim
][dim
]);
67 for (i
= 0; i
< dim
; ++i
)
68 Vector_Scale(Y
->p
[i
], M
->p
[i
]+dim
, tmp
, dim
);
70 left_hermite(M
, &H
, &Q
, &U
);
75 L
= Matrix_Alloc(dim
+1, dim
+1);
76 value_assign(L
->p
[dim
][dim
], lcm
);
77 for (i
= 0; i
< dim
; ++i
)
78 Vector_Copy(H
->p
[i
], L
->p
[i
], dim
);
86 static void Param_Vertex_Common_Denominator(Param_Vertices
*V
)
92 assert(V
->Vertex
->NbRows
> 0);
93 dim
= V
->Vertex
->NbColumns
-2;
97 value_assign(lcm
, V
->Vertex
->p
[0][dim
+1]);
98 for (i
= 1; i
< V
->Vertex
->NbRows
; ++i
)
99 value_lcm(V
->Vertex
->p
[i
][dim
+1], lcm
, &lcm
);
101 for (i
= 0; i
< V
->Vertex
->NbRows
; ++i
) {
102 if (value_eq(V
->Vertex
->p
[i
][dim
+1], lcm
))
104 value_division(V
->Vertex
->p
[i
][dim
+1], lcm
, V
->Vertex
->p
[i
][dim
+1]);
105 Vector_Scale(V
->Vertex
->p
[i
], V
->Vertex
->p
[i
],
106 V
->Vertex
->p
[i
][dim
+1], dim
+1);
107 value_assign(V
->Vertex
->p
[i
][dim
+1], lcm
);
113 static void Param_Vertex_Image(Param_Vertices
*V
, Matrix
*T
)
115 unsigned nvar
= V
->Vertex
->NbRows
;
116 unsigned nparam
= V
->Vertex
->NbColumns
- 2;
120 Param_Vertex_Common_Denominator(V
);
121 Vertex
= Matrix_Alloc(V
->Vertex
->NbRows
, V
->Vertex
->NbColumns
);
122 Matrix_Product(T
, V
->Vertex
, Vertex
);
123 for (i
= 0; i
< nvar
; ++i
) {
124 value_assign(Vertex
->p
[i
][nparam
+1], V
->Vertex
->p
[i
][nparam
+1]);
125 Vector_Normalize(Vertex
->p
[i
], nparam
+2);
127 Matrix_Free(V
->Vertex
);
131 /* Scales the parametric polyhedron with constraints *P and vertices PP
132 * such that the number of integer points can be represented by a polynomial.
133 * Both *P and P->Vertex are adapted according to the scaling.
134 * The scaling factor is returned in *det.
135 * The enumerator of the scaled parametric polyhedron should be divided
136 * by this number to obtain an approximation of the enumerator of the
137 * original parametric polyhedron.
139 * The algorithm is described in "Approximating Ehrhart Polynomials using
140 * affine transformations" by B. Meister.
142 void Param_Polyhedron_Scale_Integer_Slow(Param_Polyhedron
*PP
, Polyhedron
**P
,
143 Value
*det
, unsigned MaxRays
)
146 unsigned dim
= (*P
)->Dimension
;
149 Lattice
*L
= NULL
, *Li
;
158 nparam
= PP
->V
->Vertex
->NbColumns
- 2;
161 for (V
= PP
->V
; V
; V
= V
->next
) {
165 unsigned char *supporting
;
167 supporting
= supporting_constraints(*P
, V
, &n
);
168 M
= Matrix_Alloc(n
, (*P
)->Dimension
);
169 for (i
= 0, j
= 0; i
< (*P
)->NbConstraints
; ++i
)
171 Vector_Copy((*P
)->Constraint
[i
]+1, M
->p
[j
++], (*P
)->Dimension
);
173 L2
= extract_lattice(M
, nvar
);
179 Lattice
*L3
= LatticeJoin(L
, L2
);
186 /* apply the variable expansion to the polyhedron (constraints) */
187 expansion
= Matrix_Alloc(nvar
+ nparam
+ 1, nvar
+ nparam
+ 1);
188 for (i
= 0; i
< nvar
; ++i
)
189 Vector_Copy(L
->p
[i
], expansion
->p
[i
], nvar
);
190 for (i
= nvar
; i
< nvar
+nparam
+1; ++i
)
191 value_assign(expansion
->p
[i
][i
], L
->p
[nvar
][nvar
]);
193 *P
= Polyhedron_Preimage(*P
, expansion
, MaxRays
);
194 Matrix_Free(expansion
);
196 /* apply the variable expansion to the parametric vertices */
197 Li
= Matrix_Alloc(nvar
+1, nvar
+1);
198 ok
= Matrix_Inverse(L
, Li
);
201 assert(value_one_p(Li
->p
[nvar
][nvar
]));
202 T
= Matrix_Alloc(nvar
, nvar
);
203 value_set_si(*det
, 1);
204 for (i
= 0; i
< nvar
; ++i
) {
205 value_multiply(*det
, *det
, Li
->p
[i
][i
]);
206 Vector_Copy(Li
->p
[i
], T
->p
[i
], nvar
);
209 for (V
= PP
->V
; V
; V
= V
->next
)
210 Param_Vertex_Image(V
, T
);
214 /* Scales the parametric polyhedron with constraints *P and vertices PP
215 * such that the number of integer points can be represented by a polynomial.
216 * Both *P and P->Vertex are adapted according to the scaling.
217 * The scaling factor is returned in *det.
218 * The enumerator of the scaled parametric polyhedron should be divided
219 * by this number to obtain an approximation of the enumerator of the
220 * original parametric polyhedron.
222 * The algorithm is described in "Approximating Ehrhart Polynomials using
223 * affine transformations" by B. Meister.
225 void Param_Polyhedron_Scale_Integer_Fast(Param_Polyhedron
*PP
, Polyhedron
**P
,
226 Value
*det
, unsigned MaxRays
)
229 int nb_param
, nb_vars
;
232 Value global_var_lcm
;
236 value_set_si(*det
, 1);
240 nb_param
= PP
->D
->Domain
->Dimension
;
241 nb_vars
= PP
->V
->Vertex
->NbRows
;
243 /* Scan the vertices and make an orthogonal expansion of the variable
245 /* a- prepare the array of common denominators */
246 denoms
= Vector_Alloc(nb_vars
);
247 value_init(global_var_lcm
);
250 /* b- scan the vertices and compute the variables' global lcms */
251 for (V
= PP
->V
; V
; V
= V
->next
) {
252 for (i
= 0; i
< nb_vars
; i
++) {
253 Vector_Gcd(V
->Vertex
->p
[i
], nb_param
, &tmp
);
254 Gcd(tmp
, V
->Vertex
->p
[i
][nb_param
+1], &tmp
);
255 value_division(tmp
, V
->Vertex
->p
[i
][nb_param
+1], tmp
);
256 Lcm3(denoms
->p
[i
], tmp
, &denoms
->p
[i
]);
261 value_set_si(global_var_lcm
, 1);
262 for (i
= 0; i
< nb_vars
; i
++) {
263 value_multiply(*det
, *det
, denoms
->p
[i
]);
264 Lcm3(global_var_lcm
, denoms
->p
[i
], &global_var_lcm
);
268 for (V
= PP
->V
; V
; V
= V
->next
)
269 for (i
= 0; i
< nb_vars
; i
++) {
270 Vector_Scale(V
->Vertex
->p
[i
], V
->Vertex
->p
[i
], denoms
->p
[i
], nb_param
+1);
271 Vector_Normalize(V
->Vertex
->p
[i
], nb_param
+2);
274 /* the expansion can be actually writen as global_var_lcm.L^{-1} */
275 /* this is equivalent to multiply the rows of P by denoms_det */
276 for (i
= 0; i
< nb_vars
; i
++)
277 value_division(denoms
->p
[i
], global_var_lcm
, denoms
->p
[i
]);
279 /* OPT : we could use a vector instead of a diagonal matrix here (c- and d-).*/
280 /* c- make the quick expansion matrix */
281 expansion
= Matrix_Alloc(nb_vars
+nb_param
+1, nb_vars
+nb_param
+1);
282 for (i
= 0; i
< nb_vars
; i
++)
283 value_assign(expansion
->p
[i
][i
], denoms
->p
[i
]);
284 for (i
= nb_vars
; i
< nb_vars
+nb_param
+1; i
++)
285 value_assign(expansion
->p
[i
][i
], global_var_lcm
);
287 /* d- apply the variable expansion to the polyhedron */
289 *P
= Polyhedron_Preimage(*P
, expansion
, MaxRays
);
291 Matrix_Free(expansion
);
292 value_clear(global_var_lcm
);
296 /* adapted from mpolyhedron_inflate in PolyLib */
297 static Polyhedron
*Polyhedron_Inflate(Polyhedron
*P
, unsigned nparam
,
301 int nvar
= P
->Dimension
- nparam
;
302 Matrix
*C
= Polyhedron2Constraints(P
);
307 /* subtract the sum of the negative coefficients of each inequality */
308 for (i
= 0; i
< C
->NbRows
; ++i
) {
309 value_set_si(sum
, 0);
310 for (j
= 0; j
< nvar
; ++j
)
311 if (value_neg_p(C
->p
[i
][1+j
]))
312 value_addto(sum
, sum
, C
->p
[i
][1+j
]);
313 value_subtract(C
->p
[i
][1+P
->Dimension
], C
->p
[i
][1+P
->Dimension
], sum
);
316 P2
= Constraints2Polyhedron(C
, MaxRays
);
321 /* adapted from mpolyhedron_deflate in PolyLib */
322 static Polyhedron
*Polyhedron_Deflate(Polyhedron
*P
, unsigned nparam
,
326 int nvar
= P
->Dimension
- nparam
;
327 Matrix
*C
= Polyhedron2Constraints(P
);
332 /* subtract the sum of the positive coefficients of each inequality */
333 for (i
= 0; i
< C
->NbRows
; ++i
) {
334 value_set_si(sum
, 0);
335 for (j
= 0; j
< nvar
; ++j
)
336 if (value_pos_p(C
->p
[i
][1+j
]))
337 value_addto(sum
, sum
, C
->p
[i
][1+j
]);
338 value_subtract(C
->p
[i
][1+P
->Dimension
], C
->p
[i
][1+P
->Dimension
], sum
);
341 P2
= Constraints2Polyhedron(C
, MaxRays
);
346 Polyhedron
*scale_init(Polyhedron
*P
, Polyhedron
*C
, struct scale_data
*scaling
,
347 struct barvinok_options
*options
)
349 unsigned nparam
= C
->Dimension
;
351 value_init(scaling
->det
);
352 value_set_si(scaling
->det
, 1);
353 scaling
->save_approximation
= options
->polynomial_approximation
;
355 if (options
->polynomial_approximation
== BV_APPROX_SIGN_NONE
||
356 options
->polynomial_approximation
== BV_APPROX_SIGN_APPROX
)
359 if (options
->polynomial_approximation
== BV_APPROX_SIGN_UPPER
)
360 P
= Polyhedron_Inflate(P
, nparam
, options
->MaxRays
);
361 if (options
->polynomial_approximation
== BV_APPROX_SIGN_LOWER
)
362 P
= Polyhedron_Deflate(P
, nparam
, options
->MaxRays
);
364 /* Don't deflate/inflate again (on this polytope) */
365 options
->polynomial_approximation
= BV_APPROX_SIGN_NONE
;
370 Polyhedron
*scale(Param_Polyhedron
*PP
, Polyhedron
*P
,
371 struct scale_data
*scaling
, int free_P
,
372 struct barvinok_options
*options
)
377 MaxRays
= options
->MaxRays
;
378 POL_UNSET(options
->MaxRays
, POL_INTEGER
);
380 if (options
->scale_flags
& BV_APPROX_SCALE_FAST
)
381 Param_Polyhedron_Scale_Integer_Fast(PP
, &T
, &scaling
->det
, options
->MaxRays
);
383 Param_Polyhedron_Scale_Integer_Slow(PP
, &T
, &scaling
->det
, options
->MaxRays
);
387 options
->MaxRays
= MaxRays
;
392 void scale_finish(evalue
*e
, struct scale_data
*scaling
,
393 struct barvinok_options
*options
)
395 if (value_notone_p(scaling
->det
))
396 evalue_div(e
, scaling
->det
);
397 value_clear(scaling
->det
);
398 /* reset options that may have been changed */
399 options
->polynomial_approximation
= scaling
->save_approximation
;