2 #include <barvinok/options.h>
3 #include <barvinok/sample.h>
4 #include <barvinok/util.h>
11 Polyhedron
*P
; /* Original polyhedron or cone */
12 Polyhedron
*init
; /* Initial (under)approximation of integer hull */
14 Matrix
*F
; /* Set of already computed facets */
15 int n_F
; /* The number of computed facets */
17 /* Computes a lower bound for the objective function obj over
18 * the integer hull, possibly exploiting the already computed
19 * facets of the integer hull given in hull->F.
21 void (*set_lower_bound
)(struct integer_hull
*hull
, Value
*obj
,
22 Value
*lower
, struct barvinok_options
*options
);
25 static int matrix_add(Matrix
*M
, int n
, Value
*v
)
28 Matrix_Extend(M
, 3*(M
->NbRows
+10)/2);
29 Vector_Copy(v
, M
->p
[n
], M
->NbColumns
);
33 static int select_best(struct integer_hull
*hull
,
34 Polyhedron
*P
, Matrix
*candidates
,
35 int *n_candidates
, int *candidate
,
36 Value
*min
, Value
*max
,
37 struct barvinok_options
*options
)
40 Matrix
*M
= candidates
;
41 Vector
*lower
= Vector_Alloc(P
->NbConstraints
);
42 Vector
*upper
= Vector_Alloc(P
->NbConstraints
+2);
43 Vector
*distances
= Vector_Alloc(P
->NbConstraints
);
48 for (i
= 0; i
< P
->NbConstraints
; ++i
) {
49 if (First_Non_Zero(P
->Constraint
[i
]+1, P
->Dimension
) == -1)
51 for (j
= 0; j
< hull
->n_F
; ++j
)
52 if (Vector_Equal(hull
->F
->p
[j
]+1, P
->Constraint
[i
]+1, P
->Dimension
))
56 hull
->set_lower_bound(hull
, P
->Constraint
[i
]+1, &lower
->p
[i
], options
);
57 value_oppose(upper
->p
[i
], P
->Constraint
[i
][1+P
->Dimension
]);
58 value_subtract(distances
->p
[i
], upper
->p
[i
], lower
->p
[i
]);
59 if (value_zero_p(distances
->p
[i
]))
61 if (i_min
== -1 || value_lt(distances
->p
[i
], distances
->p
[i_min
]))
68 Vector_Free(distances
);
73 for (j
= 0, k
= 0; j
< *n_candidates
; ++j
) {
75 for (i
= 0; i
< P
->NbConstraints
; ++i
) {
76 if (value_zero_p(distances
->p
[i
]))
78 Inner_Product(M
->p
[j
], P
->Constraint
[i
]+1, P
->Dimension
,
79 &upper
->p
[P
->NbConstraints
]);
80 value_addto(upper
->p
[P
->NbConstraints
+1],
81 upper
->p
[P
->NbConstraints
],
82 P
->Constraint
[i
][1+P
->Dimension
]);
83 if (value_neg_p(upper
->p
[P
->NbConstraints
+1]))
85 if (value_lt(upper
->p
[P
->NbConstraints
], upper
->p
[i
])) {
86 value_assign(upper
->p
[i
], upper
->p
[P
->NbConstraints
]);
87 value_subtract(distances
->p
[i
], upper
->p
[i
], lower
->p
[i
]);
90 else if (value_lt(distances
->p
[i
], distances
->p
[i_min
])) {
98 Vector_Exchange(M
->p
[j
], M
->p
[k
], M
->NbColumns
);
104 value_decrement(*max
, upper
->p
[i_min
]);
105 value_assign(*min
, lower
->p
[i_min
]);
109 Vector_Free(distances
);
114 /* Return the (integer) vertices of P */
115 static Matrix
*Polyhedron_Vertices(Polyhedron
*P
)
118 Matrix
*M
= Matrix_Alloc(P
->NbRays
, P
->Dimension
+1);
120 for (i
= 0, j
= 0; i
< P
->NbRays
; ++i
) {
121 if (value_zero_p(P
->Ray
[i
][1+P
->Dimension
]))
123 assert(value_one_p(P
->Ray
[i
][1+P
->Dimension
]));
124 value_set_si(M
->p
[j
][P
->Dimension
], 1);
125 Vector_Copy(P
->Ray
[i
]+1, M
->p
[j
++], P
->Dimension
);
132 /* Extends an initial approximation hull->init of the integer hull
133 * of hull->P using generalized basis reduction.
134 * In particular, it considers each facet of the current
135 * approximation add optimizes in the direction of the normal,
136 * adding the optimal point to the approximation as well as
137 * all other points that may have been found along the way,
138 * until no facet yields any more new points.
139 * Returns a list of the vertices of this integer hull.
141 static Matrix
*gbr_hull_extend(struct integer_hull
*hull
,
142 struct barvinok_options
*options
)
145 Polyhedron
*Q
= hull
->init
;
146 Vector
*ray
= Vector_Alloc(2+Q
->Dimension
);
148 int n_candidates
= 0;
151 hull
->F
= Matrix_Alloc(Q
->NbConstraints
, 2+Q
->Dimension
);
154 candidates
= Matrix_Alloc(0, Q
->Dimension
);
159 value_set_si(ray
->p
[0], 1);
160 value_set_si(ray
->p
[1+Q
->Dimension
], 1);
164 int i
, i_min
, candidate
;
166 Value
*vertex
= NULL
;
168 i_min
= select_best(hull
, Q
, candidates
, &n_candidates
, &candidate
,
169 &min
, &max
, options
);
173 opt
= Polyhedron_Integer_Minimum(hull
->P
, Q
->Constraint
[i_min
]+1,
174 min
, max
, candidates
, &n_candidates
,
176 candidates
->NbRows
= n_candidates
;
178 hull
->n_F
= matrix_add(hull
->F
, hull
->n_F
, Q
->Constraint
[i_min
]);
182 else if (candidate
!= -1)
183 vertex
= candidates
->p
[candidate
];
188 Inner_Product(hull
->F
->p
[hull
->n_F
-1]+1, vertex
, Q
->Dimension
,
189 &hull
->F
->p
[hull
->n_F
-1][1+Q
->Dimension
]);
190 value_oppose(hull
->F
->p
[hull
->n_F
-1][1+Q
->Dimension
],
191 hull
->F
->p
[hull
->n_F
-1][1+Q
->Dimension
]);
193 Vector_Copy(vertex
, ray
->p
+1, Q
->Dimension
);
194 R
= AddRays(ray
->p
, 1, Q
, options
->MaxRays
);
202 vertices
= Polyhedron_Vertices(Q
);
211 Matrix_Free(hull
->F
);
213 Matrix_Free(candidates
);
218 /* Returns the Minkowski sum of the cone and the polytope
219 * that is the convex hull of its (integer) extremal rays.
221 static Polyhedron
*truncate_cone(Polyhedron
*C
,
222 struct barvinok_options
*options
)
228 V
= Matrix_Alloc(2*C
->NbRays
, 2+C
->Dimension
);
229 for (i
= 0; i
< C
->NbRays
; ++i
) {
230 if (value_notzero_p(C
->Ray
[i
][1+C
->Dimension
]))
232 Vector_Copy(C
->Ray
[i
], V
->p
[C
->NbRays
+i
], 1+C
->Dimension
+1);
233 Vector_Copy(C
->Ray
[i
], V
->p
[i
], 1+C
->Dimension
);
234 value_set_si(V
->p
[i
][1+C
->Dimension
], 1);
236 P
= Rays2Polyhedron(V
, options
->MaxRays
);
241 /* Frees original list and transformation matrix CV */
242 static Matrix
*transform_list_of_vertices(Matrix
*list
, Matrix
*CV
)
246 M
= Matrix_Alloc(list
->NbRows
, T
->NbColumns
);
247 Matrix_Product(list
, T
, M
);
255 /* Set the lower bound for optimizing along the normal of a facet
256 * in case of computing the integer hull of a truncated cone
257 * (i.e., a cone with the origin removed).
258 * In particular, if the constraint is one bounding the original
259 * cone, then the lower bound is zero; if it is a new constraint,
260 * then the lower bound is one.
261 * A more accurate bound can be obtained by looking at the
262 * already computed facets of the integer hull.
264 static void set_to_one(struct integer_hull
*hull
, Value
*obj
,
265 Value
*lower
, struct barvinok_options
*options
)
267 if (value_zero_p(obj
[hull
->P
->Dimension
]))
268 value_set_si(*lower
, 0);
270 value_set_si(*lower
, 1);
273 static Matrix
*gbr_hull(Polyhedron
*C
, struct barvinok_options
*options
)
277 struct integer_hull hull
;
279 POL_ENSURE_VERTICES(C
);
280 remove_all_equalities(&C
, NULL
, NULL
, &CV
, 0, options
->MaxRays
);
282 POL_ENSURE_VERTICES(C
);
285 hull
.init
= truncate_cone(C
, options
);
286 hull
.set_lower_bound
= set_to_one
;
287 vertices
= gbr_hull_extend(&hull
, options
);
290 vertices
= transform_list_of_vertices(vertices
, CV
);
297 Matrix
*Cone_Integer_Hull(Polyhedron
*C
, struct barvinok_options
*options
)
299 switch(options
->integer_hull
) {
301 return gbr_hull(C
, options
);
302 case BV_HULL_HILBERT
:
303 return Cone_Hilbert_Integer_Hull(C
, options
);
309 /* Computes initial full-dimensional approximation of the integer hull of P,
310 * or discovers an implicit equality of P.
311 * We start off with the integer vertices of P itself, if any.
312 * If there are no such vertices (available), then we simply
313 * take an arbitrary integer point in the polytope.
314 * Then we keep optimizing over normals of equalities in the description
315 * of the current approximation, until we find an equality that holds
316 * for the entire integer hull of P or until we have obtained a
317 * full-dimensional approximation.
319 static Polyhedron
*internal_polytope(Polyhedron
*P
,
320 struct barvinok_options
*options
)
324 Matrix
*vertices
= Matrix_Alloc(P
->NbRays
, P
->Dimension
+2);
326 for (i
= 0, j
= 0; i
< P
->NbRays
; ++i
) {
327 if (value_notone_p(P
->Ray
[i
][1+P
->Dimension
]))
329 Vector_Copy(P
->Ray
[i
], vertices
->p
[j
++], 2+P
->Dimension
);
331 vertices
->NbRows
= j
;
333 Vector
*sample
= Polyhedron_Sample(P
, options
);
335 value_set_si(vertices
->p
[0][1], 1);
336 Vector_Copy(sample
->p
, vertices
->p
[0]+1, P
->Dimension
+1);
338 vertices
->NbRows
= 1;
341 init
= Rays2Polyhedron(vertices
, options
->MaxRays
);
342 Matrix_Free(vertices
);
344 while (!emptyQ(init
) && init
->NbEq
) {
346 Vector
*v
= Vector_Alloc(init
->Dimension
+2);
349 value_set_si(v
->p
[0], 1);
350 Vector_Copy(init
->Constraint
[0]+1, v
->p
+1, init
->Dimension
+1);
351 value_decrement(v
->p
[1+init
->Dimension
],v
->p
[1+init
->Dimension
]);
353 Q
= AddConstraints(v
->p
, 1, P
, options
->MaxRays
);
354 sample
= Polyhedron_Sample(Q
, options
);
357 Vector_Oppose(init
->Constraint
[0]+1, v
->p
+1, init
->Dimension
+1);
358 value_decrement(v
->p
[1+init
->Dimension
],v
->p
[1+init
->Dimension
]);
360 Q
= AddConstraints(v
->p
, 1, P
, options
->MaxRays
);
361 sample
= Polyhedron_Sample(Q
, options
);
365 P
= AddConstraints(init
->Constraint
[0], 1, P
, options
->MaxRays
);
366 Polyhedron_Free(init
);
372 Vector_Copy(sample
->p
, v
->p
+1, init
->Dimension
+1);
373 Q
= AddRays(v
->p
, 1, init
, options
->MaxRays
);
374 Polyhedron_Free(init
);
384 /* Set the lower bound for optimizing along the normal of a facet
385 * in case of computing the integer hull of a polyhedron.
386 * Although obj contains the full affine objective function,
387 * the calling function expect a lower bound on the linear part only.
388 * We therefore need to subtract the constant from the computed
389 * optimum of the linear relaxation.
391 static void set_lower(struct integer_hull
*hull
, Value
*obj
,
392 Value
*lower
, struct barvinok_options
*options
)
398 value_set_si(one
, 1);
400 res
= polyhedron_opt(hull
->P
, obj
, one
, lp_min
, lower
, options
);
401 value_subtract(*lower
, *lower
, obj
[hull
->P
->Dimension
]);
402 assert(res
== lp_ok
);
407 /* Computes the vertices of the integer hull of P
409 Matrix
*Polyhedron_Integer_Hull(Polyhedron
*P
,
410 struct barvinok_options
*options
)
416 POL_ENSURE_VERTICES(P
);
417 remove_all_equalities(&P
, NULL
, NULL
, &CV
, 0, options
->MaxRays
);
419 POL_ENSURE_VERTICES(P
);
421 if (P
->Dimension
== 0) {
422 vertices
= Matrix_Alloc(1, 1);
423 value_set_si(vertices
->p
[0][0], 1);
425 init
= internal_polytope(P
, options
);
427 vertices
= Matrix_Alloc(0, P
->Dimension
+1);
428 Polyhedron_Free(init
);
429 } else if (init
->NbEq
) {
430 vertices
= Polyhedron_Integer_Hull(init
, options
);
431 Polyhedron_Free(init
);
433 struct integer_hull hull
;
436 hull
.set_lower_bound
= set_lower
;
437 vertices
= gbr_hull_extend(&hull
, options
);
442 vertices
= transform_list_of_vertices(vertices
, CV
);