1 #include <barvinok/polylib.h>
2 #include <barvinok/barvinok.h>
3 #include <barvinok/options.h>
4 #include <barvinok/util.h>
5 #include "reduce_domain.h"
9 #define ALLOC(type) (type*)malloc(sizeof(type))
10 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
12 /* returns an evalue that corresponds to
16 static evalue
*term(int param
, Value c
, Value den
)
18 evalue
*EP
= ALLOC(evalue
);
20 value_set_si(EP
->d
,0);
21 EP
->x
.p
= new_enode(polynomial
, 2, param
+ 1);
22 evalue_set_si(&EP
->x
.p
->arr
[0], 0, 1);
23 value_init(EP
->x
.p
->arr
[1].x
.n
);
24 value_assign(EP
->x
.p
->arr
[1].d
, den
);
25 value_assign(EP
->x
.p
->arr
[1].x
.n
, c
);
29 /* Computes an evalue representation of a coordinate
32 static evalue
*vertex2evalue(Value
*vertex
, int nparam
)
35 evalue
*E
= ALLOC(evalue
);
37 evalue_set(E
, vertex
[nparam
], vertex
[nparam
+1]);
38 for (i
= 0; i
< nparam
; ++i
) {
39 evalue
*t
= term(i
, vertex
[i
], vertex
[nparam
+1]);
47 static void matrix_print(evalue
***matrix
, int dim
, int *cols
,
52 for (i
= 0; i
< dim
; ++i
)
53 for (j
= 0; j
< dim
; ++j
) {
54 int k
= cols
? cols
[j
] : j
;
55 fprintf(stderr
, "%d %d: ", i
, j
);
56 print_evalue(stderr
, matrix
[i
][k
], param_names
);
57 fprintf(stderr
, "\n");
61 /* Compute determinant using Laplace's formula.
62 * In particular, the determinant is expanded along the last row.
63 * The cols array is a list of columns that remain in the currect submatrix.
65 static evalue
*determinant_cols(evalue
***matrix
, int dim
, int *cols
)
73 evalue_copy(det
, matrix
[0][cols
[0]]);
78 evalue_set_si(&mone
, -1, 1);
81 int *newcols
= ALLOCN(int, dim
-1);
82 for (j
= 1; j
< dim
; ++j
)
83 newcols
[j
-1] = cols
[j
];
84 for (j
= 0; j
< dim
; ++j
) {
86 newcols
[j
-1] = cols
[j
-1];
87 tmp
= determinant_cols(matrix
, dim
-1, newcols
);
88 emul(matrix
[dim
-1][cols
[j
]], tmp
);
95 free_evalue_refs(tmp
);
100 free_evalue_refs(&mone
);
105 static evalue
*determinant(evalue
***matrix
, int dim
)
108 int *cols
= ALLOCN(int, dim
);
111 for (i
= 0; i
< dim
; ++i
)
114 det
= determinant_cols(matrix
, dim
, cols
);
121 /* Compute the facet of P that saturates constraint c.
123 static Polyhedron
*facet(Polyhedron
*P
, int c
, unsigned MaxRays
)
126 Vector
*row
= Vector_Alloc(1+P
->Dimension
+1);
127 Vector_Copy(P
->Constraint
[c
]+1, row
->p
+1, P
->Dimension
+1);
128 F
= AddConstraints(row
->p
, 1, P
, MaxRays
);
133 /* Compute a dummy Param_Domain that contains all vertices of Param_Domain D
134 * (which contains the vertices of P) that lie on the facet obtain by
135 * saturating constraint c of P
137 static Param_Domain
*face_vertices(Param_Polyhedron
*PP
, Param_Domain
*D
,
138 Polyhedron
*P
, int c
)
142 Param_Domain
*FD
= ALLOC(Param_Domain
);
146 nv
= (PP
->nbV
- 1)/(8*sizeof(int)) + 1;
147 FD
->F
= ALLOCN(unsigned, nv
);
148 memset(FD
->F
, 0, nv
* sizeof(unsigned));
150 FORALL_PVertex_in_ParamPolyhedron(V
, D
, PP
) /* _i, _ix, _bx internal counters */
152 unsigned char *supporting
= supporting_constraints(P
, V
, &n
);
156 END_FORALL_PVertex_in_ParamPolyhedron
;
161 /* Substitute parameters by the corresponding element in subs
163 static evalue
*evalue_substitute(evalue
*e
, evalue
**subs
)
169 if (value_notzero_p(e
->d
)) {
175 assert(e
->x
.p
->type
== polynomial
);
178 for (i
= e
->x
.p
->size
-1; i
> 0; --i
) {
179 c
= evalue_substitute(&e
->x
.p
->arr
[i
], subs
);
183 emul(subs
[e
->x
.p
->pos
-1], res
);
185 c
= evalue_substitute(&e
->x
.p
->arr
[0], subs
);
193 /* Plug in the parametric vertex V in the constraint constraint.
194 * The result is stored in row, with the denominator in position 0.
196 static void Param_Inner_Product(Value
*constraint
, Matrix
*Vertex
,
199 unsigned nparam
= Vertex
->NbColumns
- 2;
200 unsigned nvar
= Vertex
->NbRows
;
204 value_set_si(row
[0], 1);
205 Vector_Set(row
+1, 0, nparam
+1);
210 for (j
= 0 ; j
< nvar
; ++j
) {
211 value_set_si(tmp
, 1);
212 value_assign(tmp2
, constraint
[1+j
]);
213 if (value_ne(row
[0], Vertex
->p
[j
][nparam
+1])) {
214 value_assign(tmp
, row
[0]);
215 value_lcm(row
[0], Vertex
->p
[j
][nparam
+1], &row
[0]);
216 value_division(tmp
, row
[0], tmp
);
217 value_multiply(tmp2
, tmp2
, row
[0]);
218 value_division(tmp2
, tmp2
, Vertex
->p
[j
][nparam
+1]);
220 Vector_Combine(row
+1, Vertex
->p
[j
], row
+1, tmp
, tmp2
, nparam
+1);
222 value_set_si(tmp
, 1);
223 Vector_Combine(row
+1, constraint
+1+nvar
, row
+1, tmp
, row
[0], nparam
+1);
229 /* Computes point in pameter space where polyhedron is non-empty.
230 * For each of the parametric vertices, and each of the facets
231 * not (always) containing the vertex, we remove the parameter
232 * values for which the facet does contain the vertex.
234 static evalue
**non_empty_point(Param_Polyhedron
*PP
, Param_Domain
*D
,
235 Polyhedron
*P
, Polyhedron
*C
, unsigned MaxRays
)
238 unsigned dim
= P
->Dimension
;
239 unsigned nparam
= C
->Dimension
;
240 unsigned nvar
= dim
- nparam
;
241 Polyhedron
*RD
, *cut
, *tmp
;
245 unsigned cut_MaxRays
= MaxRays
;
248 nv
= (PP
->nbV
- 1)/(8*sizeof(int)) + 1;
250 POL_UNSET(cut_MaxRays
, POL_INTEGER
);
252 M
= Matrix_Alloc(1, nparam
+2);
254 FORALL_PVertex_in_ParamPolyhedron(V
, D
, PP
) /* _ix, _bx internal counters */
255 for (i
= P
->NbEq
; i
< P
->NbConstraints
; ++i
) {
256 if (First_Non_Zero(P
->Constraint
[i
]+1, nvar
) == -1)
258 Param_Inner_Product(P
->Constraint
[i
], V
->Vertex
, M
->p
[0]);
259 if (First_Non_Zero(M
->p
[0]+1, nparam
) == -1)
261 * or non-supporting facet independent of params
264 value_set_si(M
->p
[0][0], 0);
265 cut
= Constraints2Polyhedron(M
, cut_MaxRays
);
266 tmp
= DomainDifference(RD
, cut
, MaxRays
);
270 Polyhedron_Free(cut
);
274 END_FORALL_PVertex_in_ParamPolyhedron
;
277 POL_ENSURE_VERTICES(RD
);
281 point
= ALLOCN(evalue
*, nvar
);
282 for (i
= 0; i
< RD
->NbRays
; ++i
)
283 if (value_notzero_p(RD
->Ray
[i
][1+nparam
]))
285 assert(i
< RD
->NbRays
);
286 for (j
= 0; j
< nparam
; ++j
) {
287 point
[j
] = ALLOC(evalue
);
288 value_init(point
[j
]->d
);
289 evalue_set(point
[j
], RD
->Ray
[i
][1+j
], RD
->Ray
[i
][1+nparam
]);
299 static Matrix
*barycenter(Param_Polyhedron
*PP
, Param_Domain
*D
)
302 Matrix
*center
= NULL
;
312 FORALL_PVertex_in_ParamPolyhedron(V
, D
, PP
)
315 center
= Matrix_Copy(V
->Vertex
);
316 nparam
= center
->NbColumns
- 2;
318 for (i
= 0; i
< center
->NbRows
; ++i
) {
319 value_assign(fc
, center
->p
[i
][nparam
+1]);
320 value_lcm(fc
, V
->Vertex
->p
[i
][nparam
+1],
321 ¢er
->p
[i
][nparam
+1]);
322 value_division(fc
, center
->p
[i
][nparam
+1], fc
);
323 value_division(fv
, center
->p
[i
][nparam
+1],
324 V
->Vertex
->p
[i
][nparam
+1]);
325 Vector_Combine(center
->p
[i
], V
->Vertex
->p
[i
], center
->p
[i
],
329 END_FORALL_PVertex_in_ParamPolyhedron
;
334 value_set_si(denom
, nbV
);
335 for (i
= 0; i
< center
->NbRows
; ++i
) {
336 value_multiply(center
->p
[i
][nparam
+1], center
->p
[i
][nparam
+1], denom
);
337 Vector_Normalize(center
->p
[i
], nparam
+2);
344 /* Compute dim! times the volume of polyhedron F in Param_Domain D.
345 * If F is a simplex, then the volume is computed of a recursive pyramid
346 * over F with the points already in matrix.
347 * Otherwise, the barycenter of F is added to matrix and the function
348 * is called recursively on the facets of F.
350 * The first row of matrix contain the _negative_ of the first point.
351 * The remaining rows of matrix contain the distance of the corresponding
352 * point to the first point.
354 static evalue
*volume_in_domain(Param_Polyhedron
*PP
, Param_Domain
*D
,
355 unsigned dim
, evalue
***matrix
,
356 evalue
**point
, Polyhedron
*C
,
357 int row
, Polyhedron
*F
, unsigned MaxRays
);
359 static evalue
*volume_triangulate(Param_Polyhedron
*PP
, Param_Domain
*D
,
360 unsigned dim
, evalue
***matrix
,
361 evalue
**point
, Polyhedron
*C
,
362 int row
, Polyhedron
*F
, unsigned MaxRays
)
369 unsigned cut_MaxRays
= MaxRays
;
370 unsigned nparam
= C
->Dimension
;
373 POL_UNSET(cut_MaxRays
, POL_INTEGER
);
376 evalue_set_si(&mone
, -1, 1);
378 center
= barycenter(PP
, D
);
379 for (j
= 0; j
< dim
; ++j
)
380 matrix
[row
][j
] = vertex2evalue(center
->p
[j
], center
->NbColumns
- 2);
383 for (j
= 0; j
< dim
; ++j
)
384 emul(&mone
, matrix
[row
][j
]);
386 for (j
= 0; j
< dim
; ++j
)
387 eadd(matrix
[0][j
], matrix
[row
][j
]);
391 M
= Matrix_Alloc(1, nparam
+2);
394 POL_ENSURE_FACETS(F
);
395 for (j
= F
->NbEq
; j
< F
->NbConstraints
; ++j
) {
399 if (First_Non_Zero(F
->Constraint
[j
]+1, dim
) == -1)
406 Param_Inner_Product(F
->Constraint
[j
], center
, M
->p
[0]);
407 pos
= First_Non_Zero(M
->p
[0]+1, nparam
+1);
409 /* barycenter always lies on facet */
414 value_set_si(M
->p
[0][0], 0);
415 cut
= Constraints2Polyhedron(M
, cut_MaxRays
);
416 FC
= DomainDifference(C
, cut
, MaxRays
);
417 Polyhedron_Free(cut
);
418 POL_ENSURE_VERTICES(FC
);
420 /* barycenter lies on facet for all parameters in C */
426 FF
= facet(F
, j
, MaxRays
);
427 FD
= face_vertices(PP
, D
, F
, j
);
428 tmp
= volume_in_domain(PP
, FD
, dim
, matrix
, point
, FC
,
436 free_evalue_refs(tmp
);
440 Param_Domain_Free(FD
);
447 for (j
= 0; j
< dim
; ++j
) {
448 free_evalue_refs(matrix
[row
][j
]);
449 free(matrix
[row
][j
]);
452 free_evalue_refs(&mone
);
456 static evalue
*volume_simplex(Param_Polyhedron
*PP
, Param_Domain
*D
,
457 unsigned dim
, evalue
***matrix
,
459 int row
, unsigned MaxRays
)
467 return evalue_zero();
470 evalue_set_si(&mone
, -1, 1);
473 FORALL_PVertex_in_ParamPolyhedron(V
, D
, PP
) /* _ix, _bx internal counters */
474 for (j
= 0; j
< dim
; ++j
) {
475 matrix
[i
][j
] = vertex2evalue(V
->Vertex
->p
[j
],
476 V
->Vertex
->NbColumns
- 2);
478 emul(&mone
, matrix
[i
][j
]);
480 eadd(matrix
[0][j
], matrix
[i
][j
]);
483 END_FORALL_PVertex_in_ParamPolyhedron
;
485 vol
= determinant(matrix
+1, dim
);
487 val
= evalue_substitute(vol
, point
);
489 assert(value_notzero_p(val
->d
));
490 assert(value_notzero_p(val
->x
.n
));
491 if (value_neg_p(val
->x
.n
))
494 free_evalue_refs(val
);
497 for (i
= row
; i
< dim
+1; ++i
) {
498 for (j
= 0; j
< dim
; ++j
) {
499 free_evalue_refs(matrix
[i
][j
]);
504 free_evalue_refs(&mone
);
509 static evalue
*volume_in_domain(Param_Polyhedron
*PP
, Param_Domain
*D
,
510 unsigned dim
, evalue
***matrix
,
511 evalue
**point
, Polyhedron
*C
,
512 int row
, Polyhedron
*F
, unsigned MaxRays
)
517 int point_computed
= 0;
520 point
= non_empty_point(PP
, D
, F
, C
, MaxRays
);
526 FORALL_PVertex_in_ParamPolyhedron(V
, D
, PP
)
528 END_FORALL_PVertex_in_ParamPolyhedron
;
530 if (nbV
> (dim
-row
) + 1)
531 vol
= volume_triangulate(PP
, D
, dim
, matrix
, point
, C
,
534 assert(nbV
== (dim
-row
) + 1);
535 vol
= volume_simplex(PP
, D
, dim
, matrix
, point
, row
, MaxRays
);
538 if (point_computed
) {
540 for (i
= 0; i
< C
->Dimension
; ++i
) {
541 free_evalue_refs(point
[i
]);
550 evalue
* Param_Polyhedron_Volume(Polyhedron
*P
, Polyhedron
* C
,
551 struct barvinok_options
*options
)
554 unsigned nparam
= C
->Dimension
;
555 unsigned nvar
= P
->Dimension
- C
->Dimension
;
556 Param_Polyhedron
*PP
;
557 unsigned PP_MaxRays
= options
->MaxRays
;
558 unsigned rat_MaxRays
= options
->MaxRays
;
563 struct section
{ Polyhedron
*D
; evalue
*E
; } *s
;
565 Param_Domain
*D
, *next
;
568 if (options
->polynomial_approximation
== BV_APPROX_SIGN_NONE
)
569 options
->polynomial_approximation
= BV_APPROX_SIGN_APPROX
;
571 if (options
->polynomial_approximation
!= BV_APPROX_SIGN_APPROX
) {
572 int pa
= options
->polynomial_approximation
;
573 assert(pa
== BV_APPROX_SIGN_UPPER
|| pa
== BV_APPROX_SIGN_LOWER
);
575 P
= Polyhedron_Flate(P
, nparam
, pa
== BV_APPROX_SIGN_UPPER
,
578 /* Don't deflate/inflate again (on this polytope) */
579 options
->polynomial_approximation
= BV_APPROX_SIGN_APPROX
;
580 vol
= barvinok_enumerate_with_options(P
, C
, options
);
581 options
->polynomial_approximation
= pa
;
587 if (PP_MaxRays
& POL_NO_DUAL
)
590 POL_UNSET(rat_MaxRays
, POL_INTEGER
);
593 Factorial(nvar
, &fact
);
595 PP
= Polyhedron2Param_Domain(P
, C
, PP_MaxRays
);
597 for (nd
= 0, D
= PP
->D
; D
; ++nd
, D
= D
->next
);
598 s
= ALLOCN(struct section
, nd
);
599 fVD
= ALLOCN(Polyhedron
*, nd
);
601 matrix
= ALLOCN(evalue
**, nvar
+1);
602 for (i
= 0; i
< nvar
+1; ++i
)
603 matrix
[i
] = ALLOCN(evalue
*, nvar
);
605 for (nd
= 0, D
= PP
->D
; D
; D
= next
) {
606 Polyhedron
*rVD
= reduce_domain(D
->Domain
, NULL
, NULL
, fVD
, nd
, options
);
613 CA
= align_context(D
->Domain
, P
->Dimension
, options
->MaxRays
);
614 F
= DomainIntersection(P
, CA
, rat_MaxRays
);
618 s
[nd
].E
= volume_in_domain(PP
, D
, nvar
, matrix
, NULL
, rVD
,
621 evalue_div(s
[nd
].E
, fact
);
628 value_set_si(vol
->d
, 0);
631 evalue_set_si(vol
, 0, 1);
633 vol
->x
.p
= new_enode(partition
, 2*nd
, C
->Dimension
);
634 for (i
= 0; i
< nd
; ++i
) {
635 EVALUE_SET_DOMAIN(vol
->x
.p
->arr
[2*i
], s
[i
].D
);
636 value_clear(vol
->x
.p
->arr
[2*i
+1].d
);
637 vol
->x
.p
->arr
[2*i
+1] = *s
[i
].E
;
645 for (i
= 0; i
< nvar
+1; ++i
)
648 Param_Polyhedron_Free(PP
);