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 fprintf(stderr
, "%d %d: ", i
, j
);
55 print_evalue(stderr
, matrix
[i
][cols
[j
]], param_names
);
56 fprintf(stderr
, "\n");
60 /* Compute determinant using Laplace's formula.
61 * In particular, the determinant is expanded along the last row.
62 * The cols array is a list of columns that remain in the currect submatrix.
64 static evalue
*determinant_cols(evalue
***matrix
, int dim
, int *cols
)
72 evalue_copy(det
, matrix
[0][cols
[0]]);
77 evalue_set_si(&mone
, -1, 1);
80 int *newcols
= ALLOCN(int, dim
-1);
81 for (j
= 1; j
< dim
; ++j
)
82 newcols
[j
-1] = cols
[j
];
83 for (j
= 0; j
< dim
; ++j
) {
85 newcols
[j
-1] = cols
[j
-1];
86 tmp
= determinant_cols(matrix
, dim
-1, newcols
);
87 emul(matrix
[dim
-1][cols
[j
]], tmp
);
94 free_evalue_refs(tmp
);
99 free_evalue_refs(&mone
);
104 static evalue
*determinant(evalue
***matrix
, int dim
)
107 int *cols
= ALLOCN(int, dim
);
110 for (i
= 0; i
< dim
; ++i
)
113 det
= determinant_cols(matrix
, dim
, cols
);
120 /* Compute the facet of P that saturates constraint c.
122 static Polyhedron
*facet(Polyhedron
*P
, int c
, unsigned MaxRays
)
125 Vector
*row
= Vector_Alloc(1+P
->Dimension
+1);
126 Vector_Copy(P
->Constraint
[c
]+1, row
->p
+1, P
->Dimension
+1);
127 F
= AddConstraints(row
->p
, 1, P
, MaxRays
);
132 /* Compute a dummy Param_Domain that contains all vertices of Param_Domain D
133 * (which contains the vertices of P) that lie on the facet obtain by
134 * saturating constraint c of P
136 static Param_Domain
*face_vertices(Param_Polyhedron
*PP
, Param_Domain
*D
,
137 Polyhedron
*P
, int c
)
141 Param_Domain
*FD
= ALLOC(Param_Domain
);
145 nv
= (PP
->nbV
- 1)/(8*sizeof(int)) + 1;
146 FD
->F
= ALLOCN(unsigned, nv
);
147 memset(FD
->F
, 0, nv
* sizeof(unsigned));
149 FORALL_PVertex_in_ParamPolyhedron(V
, D
, PP
) /* _i, _ix, _bx internal counters */
151 unsigned char *supporting
= supporting_constraints(P
, V
, &n
);
155 END_FORALL_PVertex_in_ParamPolyhedron
;
160 /* Substitute parameters by the corresponding element in subs
162 static evalue
*evalue_substitute(evalue
*e
, evalue
**subs
)
168 if (value_notzero_p(e
->d
)) {
174 assert(e
->x
.p
->type
== polynomial
);
177 for (i
= e
->x
.p
->size
-1; i
> 0; --i
) {
178 c
= evalue_substitute(&e
->x
.p
->arr
[i
], subs
);
182 emul(subs
[e
->x
.p
->pos
-1], res
);
184 c
= evalue_substitute(&e
->x
.p
->arr
[0], subs
);
192 /* Compute dim! times the volume of polyhedron F in Param_Domain D.
193 * If F is a simplex, then the volume is computed of a recursive pyramid
194 * over F with the points already in matrix.
195 * Otherwise, the barycenter of F is added to matrix and the function
196 * is called recursively on the facets of F.
198 * The first row of matrix contain the _negative_ of the first point.
199 * The remaining rows of matrix contain the distance of the corresponding
200 * point to the first point.
202 static evalue
*volume_in_domain(Param_Polyhedron
*PP
, Param_Domain
*D
,
203 unsigned dim
, evalue
***matrix
,
204 evalue
**point
, int *removed
,
205 int row
, Polyhedron
*F
, unsigned MaxRays
);
207 static evalue
*volume_triangulate(Param_Polyhedron
*PP
, Param_Domain
*D
,
208 unsigned dim
, evalue
***matrix
,
209 evalue
**point
, int *removed
,
210 int row
, Polyhedron
*F
, unsigned MaxRays
)
220 evalue_set_si(&mone
, -1, 1);
223 FORALL_PVertex_in_ParamPolyhedron(V
, D
, PP
)
224 for (j
= 0; j
< dim
; ++j
) {
225 tmp
= vertex2evalue(V
->Vertex
->p
[j
], V
->Vertex
->NbColumns
- 2);
227 matrix
[row
][j
] = tmp
;
229 eadd(tmp
, matrix
[row
][j
]);
230 free_evalue_refs(tmp
);
235 END_FORALL_PVertex_in_ParamPolyhedron
;
237 value_set_si(denom
, nbV
);
238 for (j
= 0; j
< dim
; ++j
)
239 evalue_div(matrix
[row
][j
], denom
);
243 for (j
= 0; j
< dim
; ++j
)
244 emul(&mone
, matrix
[row
][j
]);
246 for (j
= 0; j
< dim
; ++j
)
247 eadd(matrix
[0][j
], matrix
[row
][j
]);
251 POL_ENSURE_FACETS(F
);
252 for (j
= F
->NbEq
; j
< F
->NbConstraints
; ++j
) {
255 if (First_Non_Zero(F
->Constraint
[j
]+1, dim
) == -1)
257 FF
= facet(F
, j
, MaxRays
);
258 FD
= face_vertices(PP
, D
, F
, j
);
259 tmp
= volume_in_domain(PP
, FD
, dim
, matrix
, point
, removed
,
265 free_evalue_refs(tmp
);
269 Param_Domain_Free(FD
);
272 for (j
= 0; j
< dim
; ++j
) {
273 free_evalue_refs(matrix
[row
][j
]);
274 free(matrix
[row
][j
]);
277 free_evalue_refs(&mone
);
281 static evalue
*volume_in_domain(Param_Polyhedron
*PP
, Param_Domain
*D
,
282 unsigned dim
, evalue
***matrix
,
283 evalue
**point
, int *removed
,
284 int row
, Polyhedron
*F
, unsigned MaxRays
)
294 FORALL_PVertex_in_ParamPolyhedron(V
, D
, PP
)
296 END_FORALL_PVertex_in_ParamPolyhedron
;
298 if (nbV
> (dim
-row
) + 1)
299 return volume_triangulate(PP
, D
, dim
, matrix
, point
, removed
,
302 assert(nbV
== (dim
-row
) + 1);
305 evalue_set_si(&mone
, -1, 1);
308 FORALL_PVertex_in_ParamPolyhedron(V
, D
, PP
) /* _ix, _bx internal counters */
309 if (removed
[_ix
] & _bx
)
311 for (j
= 0; j
< dim
; ++j
) {
312 matrix
[i
][j
] = vertex2evalue(V
->Vertex
->p
[j
],
313 V
->Vertex
->NbColumns
- 2);
315 emul(&mone
, matrix
[i
][j
]);
317 eadd(matrix
[0][j
], matrix
[i
][j
]);
320 END_FORALL_PVertex_in_ParamPolyhedron
;
322 vol
= determinant(matrix
+1, dim
);
324 val
= evalue_substitute(vol
, point
);
326 assert(value_notzero_p(val
->d
));
327 if (value_zero_p(val
->x
.n
)) {
333 } else if (value_neg_p(val
->x
.n
))
336 free_evalue_refs(val
);
339 for (i
= row
; i
< dim
+1; ++i
) {
340 for (j
= 0; j
< dim
; ++j
) {
341 free_evalue_refs(matrix
[i
][j
]);
346 free_evalue_refs(&mone
);
351 /* Plug in the parametric vertex V in the constraint constraint.
352 * The result is stored in row, with the denominator in position 0.
354 static void Param_Inner_Product(Value
*constraint
, Param_Vertices
*V
,
357 unsigned nparam
= V
->Vertex
->NbColumns
- 2;
358 unsigned nvar
= V
->Vertex
->NbRows
;
362 value_set_si(row
[0], 1);
363 Vector_Set(row
+1, 0, nparam
+1);
368 for (j
= 0 ; j
< nvar
; ++j
) {
369 value_set_si(tmp
, 1);
370 value_assign(tmp2
, constraint
[1+j
]);
371 if (value_ne(row
[0], V
->Vertex
->p
[j
][nparam
+1])) {
372 value_assign(tmp
, row
[0]);
373 value_lcm(row
[0], V
->Vertex
->p
[j
][nparam
+1], &row
[0]);
374 value_division(tmp
, row
[0], tmp
);
375 value_multiply(tmp2
, tmp2
, row
[0]);
376 value_division(tmp2
, tmp2
, V
->Vertex
->p
[j
][nparam
+1]);
378 Vector_Combine(row
+1, V
->Vertex
->p
[j
], row
+1, tmp
, tmp2
, nparam
+1);
380 value_set_si(tmp
, 1);
381 Vector_Combine(row
+1, constraint
+1+nvar
, row
+1, tmp
, row
[0], nparam
+1);
387 /* Computes point in pameter space where polyhedron is non-empty.
388 * For each of the parametric vertices, and each of the facets
389 * not (always) containing the vertex, we remove the parameter
390 * values for which the facet does contain the vertex.
392 static evalue
**non_empty_point(Param_Polyhedron
*PP
, Param_Domain
*D
,
393 Polyhedron
*P
, int **removed
, unsigned MaxRays
)
396 unsigned dim
= P
->Dimension
;
397 unsigned nparam
= D
->Domain
->Dimension
;
398 unsigned nvar
= dim
- nparam
;
399 Polyhedron
*RD
, *cut
, *tmp
;
403 unsigned cut_MaxRays
= MaxRays
;
406 nv
= (PP
->nbV
- 1)/(8*sizeof(int)) + 1;
407 removed
[0] = ALLOCN(unsigned, nv
);
408 memset(removed
[0], 0, nv
* sizeof(unsigned));
410 POL_UNSET(cut_MaxRays
, POL_INTEGER
);
412 M
= Matrix_Alloc(1, nparam
+2);
414 FORALL_PVertex_in_ParamPolyhedron(V
, D
, PP
) /* _ix, _bx internal counters */
415 Polyhedron
*VD
= D
->Domain
;
416 for (i
= P
->NbEq
; i
< P
->NbConstraints
; ++i
) {
417 if (First_Non_Zero(P
->Constraint
[i
]+1, nvar
) == -1)
419 Param_Inner_Product(P
->Constraint
[i
], V
, M
->p
[0]);
420 if (First_Non_Zero(M
->p
[0]+1, nparam
) == -1)
422 * or non-supporting facet independent of params
425 value_set_si(M
->p
[0][0], 0);
426 cut
= Constraints2Polyhedron(M
, cut_MaxRays
);
427 tmp
= DomainDifference(VD
, cut
, MaxRays
);
431 Polyhedron_Free(cut
);
434 VD
= DomainConstraintSimplify(VD
, MaxRays
);
435 POL_ENSURE_FACETS(VD
);
438 removed
[0][_ix
] |= _bx
;
443 tmp
= DomainIntersection(RD
, VD
, MaxRays
);
451 END_FORALL_PVertex_in_ParamPolyhedron
;
457 POL_ENSURE_VERTICES(RD
);
458 point
= ALLOCN(evalue
*, nvar
);
459 for (i
= 0; i
< RD
->NbRays
; ++i
)
460 if (value_notzero_p(RD
->Ray
[i
][1+nparam
]))
462 assert(i
< RD
->NbRays
);
463 for (j
= 0; j
< nparam
; ++j
) {
464 point
[j
] = ALLOC(evalue
);
465 value_init(point
[j
]->d
);
466 evalue_set(point
[j
], RD
->Ray
[i
][1+j
], RD
->Ray
[i
][1+nparam
]);
476 evalue
* Param_Polyhedron_Volume(Polyhedron
*P
, Polyhedron
* C
,
477 struct barvinok_options
*options
)
480 unsigned nparam
= C
->Dimension
;
481 unsigned nvar
= P
->Dimension
- C
->Dimension
;
482 Param_Polyhedron
*PP
;
483 unsigned PP_MaxRays
= options
->MaxRays
;
484 unsigned rat_MaxRays
= options
->MaxRays
;
489 struct section
{ Polyhedron
*D
; evalue
*E
; } *s
;
491 Param_Domain
*D
, *next
;
494 if (options
->polynomial_approximation
!= BV_APPROX_SIGN_APPROX
) {
495 int pa
= options
->polynomial_approximation
;
496 assert(pa
== BV_APPROX_SIGN_UPPER
|| pa
== BV_APPROX_SIGN_LOWER
);
498 P
= Polyhedron_Flate(P
, nparam
, pa
== BV_APPROX_SIGN_UPPER
,
501 /* Don't deflate/inflate again (on this polytope) */
502 options
->polynomial_approximation
= BV_APPROX_SIGN_APPROX
;
503 vol
= barvinok_enumerate_with_options(P
, C
, options
);
504 options
->polynomial_approximation
= pa
;
510 if (PP_MaxRays
& POL_NO_DUAL
)
513 POL_UNSET(rat_MaxRays
, POL_INTEGER
);
516 Factorial(nvar
, &fact
);
518 PP
= Polyhedron2Param_Domain(P
, C
, PP_MaxRays
);
520 for (nd
= 0, D
= PP
->D
; D
; ++nd
, D
= D
->next
);
521 s
= ALLOCN(struct section
, nd
);
522 fVD
= ALLOCN(Polyhedron
*, nd
);
524 matrix
= ALLOCN(evalue
**, nvar
+1);
525 for (i
= 0; i
< nvar
+1; ++i
)
526 matrix
[i
] = ALLOCN(evalue
*, nvar
);
528 for (nd
= 0, D
= PP
->D
; D
; D
= next
) {
531 Polyhedron
*rVD
= reduce_domain(D
->Domain
, NULL
, NULL
, fVD
, nd
, options
);
538 CA
= align_context(D
->Domain
, P
->Dimension
, options
->MaxRays
);
539 F
= DomainIntersection(P
, CA
, rat_MaxRays
);
542 point
= non_empty_point(PP
, D
, F
, &removed
, options
->MaxRays
);
545 Domain_Free(fVD
[nd
]);
552 s
[nd
].E
= volume_in_domain(PP
, D
, nvar
, matrix
, point
, removed
,
555 evalue_div(s
[nd
].E
, fact
);
557 for (i
= 0; i
< nparam
; ++i
) {
558 free_evalue_refs(point
[i
]);
569 value_set_si(vol
->d
, 0);
572 evalue_set_si(vol
, 0, 1);
574 vol
->x
.p
= new_enode(partition
, 2*nd
, C
->Dimension
);
575 for (i
= 0; i
< nd
; ++i
) {
576 EVALUE_SET_DOMAIN(vol
->x
.p
->arr
[2*i
], s
[i
].D
);
577 value_clear(vol
->x
.p
->arr
[2*i
+1].d
);
578 vol
->x
.p
->arr
[2*i
+1] = *s
[i
].E
;
586 for (i
= 0; i
< nvar
+1; ++i
)
589 Param_Polyhedron_Free(PP
);