add isl_basic_map_add_constraint
[isl.git] / isl_convex_hull.c
blob7fa1e38d168277e5c452adcbbe357940e9870e16
1 #include "isl_lp.h"
2 #include "isl_map.h"
3 #include "isl_map_private.h"
4 #include "isl_mat.h"
5 #include "isl_set.h"
6 #include "isl_seq.h"
7 #include "isl_equalities.h"
9 static struct isl_basic_set *uset_convex_hull_wrap(struct isl_set *set);
11 static void swap_ineq(struct isl_basic_map *bmap, unsigned i, unsigned j)
13 isl_int *t;
15 if (i != j) {
16 t = bmap->ineq[i];
17 bmap->ineq[i] = bmap->ineq[j];
18 bmap->ineq[j] = t;
22 /* Return 1 if constraint c is redundant with respect to the constraints
23 * in bmap. If c is a lower [upper] bound in some variable and bmap
24 * does not have a lower [upper] bound in that variable, then c cannot
25 * be redundant and we do not need solve any lp.
27 int isl_basic_map_constraint_is_redundant(struct isl_basic_map **bmap,
28 isl_int *c, isl_int *opt_n, isl_int *opt_d)
30 enum isl_lp_result res;
31 unsigned total;
32 int i, j;
34 if (!bmap)
35 return -1;
37 total = isl_basic_map_total_dim(*bmap);
38 for (i = 0; i < total; ++i) {
39 int sign;
40 if (isl_int_is_zero(c[1+i]))
41 continue;
42 sign = isl_int_sgn(c[1+i]);
43 for (j = 0; j < (*bmap)->n_ineq; ++j)
44 if (sign == isl_int_sgn((*bmap)->ineq[j][1+i]))
45 break;
46 if (j == (*bmap)->n_ineq)
47 break;
49 if (i < total)
50 return 0;
52 res = isl_solve_lp(*bmap, 0, c+1, (*bmap)->ctx->one, opt_n, opt_d);
53 if (res == isl_lp_unbounded)
54 return 0;
55 if (res == isl_lp_error)
56 return -1;
57 if (res == isl_lp_empty) {
58 *bmap = isl_basic_map_set_to_empty(*bmap);
59 return 0;
61 if (opt_d)
62 isl_int_addmul(*opt_n, *opt_d, c[0]);
63 else
64 isl_int_add(*opt_n, *opt_n, c[0]);
65 return !isl_int_is_neg(*opt_n);
68 int isl_basic_set_constraint_is_redundant(struct isl_basic_set **bset,
69 isl_int *c, isl_int *opt_n, isl_int *opt_d)
71 return isl_basic_map_constraint_is_redundant(
72 (struct isl_basic_map **)bset, c, opt_n, opt_d);
75 /* Compute the convex hull of a basic map, by removing the redundant
76 * constraints. If the minimal value along the normal of a constraint
77 * is the same if the constraint is removed, then the constraint is redundant.
79 * Alternatively, we could have intersected the basic map with the
80 * corresponding equality and the checked if the dimension was that
81 * of a facet.
83 struct isl_basic_map *isl_basic_map_convex_hull(struct isl_basic_map *bmap)
85 int i;
86 isl_int opt_n;
87 isl_int opt_d;
88 struct isl_ctx *ctx;
90 bmap = isl_basic_map_implicit_equalities(bmap);
91 if (!bmap)
92 return NULL;
94 if (F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
95 return bmap;
96 if (F_ISSET(bmap, ISL_BASIC_MAP_NO_REDUNDANT))
97 return bmap;
99 ctx = bmap->ctx;
100 isl_int_init(opt_n);
101 isl_int_init(opt_d);
102 for (i = bmap->n_ineq-1; i >= 0; --i) {
103 int redundant;
104 swap_ineq(bmap, i, bmap->n_ineq-1);
105 bmap->n_ineq--;
106 redundant = isl_basic_map_constraint_is_redundant(&bmap,
107 bmap->ineq[bmap->n_ineq], &opt_n, &opt_d);
108 if (redundant == -1)
109 goto error;
110 if (F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
111 break;
112 bmap->n_ineq++;
113 swap_ineq(bmap, i, bmap->n_ineq-1);
114 if (redundant)
115 isl_basic_map_drop_inequality(bmap, i);
117 isl_int_clear(opt_n);
118 isl_int_clear(opt_d);
120 F_SET(bmap, ISL_BASIC_MAP_NO_REDUNDANT);
121 return bmap;
122 error:
123 isl_int_clear(opt_n);
124 isl_int_clear(opt_d);
125 isl_basic_map_free(bmap);
126 return NULL;
129 struct isl_basic_set *isl_basic_set_convex_hull(struct isl_basic_set *bset)
131 return (struct isl_basic_set *)
132 isl_basic_map_convex_hull((struct isl_basic_map *)bset);
135 /* Check if the set set is bound in the direction of the affine
136 * constraint c and if so, set the constant term such that the
137 * resulting constraint is a bounding constraint for the set.
139 static int uset_is_bound(struct isl_ctx *ctx, struct isl_set *set,
140 isl_int *c, unsigned len)
142 int first;
143 int j;
144 isl_int opt;
145 isl_int opt_denom;
147 isl_int_init(opt);
148 isl_int_init(opt_denom);
149 first = 1;
150 for (j = 0; j < set->n; ++j) {
151 enum isl_lp_result res;
153 if (F_ISSET(set->p[j], ISL_BASIC_SET_EMPTY))
154 continue;
156 res = isl_solve_lp((struct isl_basic_map*)set->p[j],
157 0, c+1, ctx->one, &opt, &opt_denom);
158 if (res == isl_lp_unbounded)
159 break;
160 if (res == isl_lp_error)
161 goto error;
162 if (res == isl_lp_empty) {
163 set->p[j] = isl_basic_set_set_to_empty(set->p[j]);
164 if (!set->p[j])
165 goto error;
166 continue;
168 if (!isl_int_is_one(opt_denom))
169 isl_seq_scale(c, c, opt_denom, len);
170 if (first || isl_int_lt(opt, c[0]))
171 isl_int_set(c[0], opt);
172 first = 0;
174 isl_int_clear(opt);
175 isl_int_clear(opt_denom);
176 isl_int_neg(c[0], c[0]);
177 return j >= set->n;
178 error:
179 isl_int_clear(opt);
180 isl_int_clear(opt_denom);
181 return -1;
184 /* Check if "c" is a direction with both a lower bound and an upper
185 * bound in "set" that is independent of the previously found "n"
186 * bounds in "dirs".
187 * If so, add it to the list, with the negative of the lower bound
188 * in the constant position, i.e., such that c corresponds to a bounding
189 * hyperplane (but not necessarily a facet).
191 static int is_independent_bound(struct isl_ctx *ctx,
192 struct isl_set *set, isl_int *c,
193 struct isl_mat *dirs, int n)
195 int is_bound;
196 int i = 0;
198 isl_seq_cpy(dirs->row[n]+1, c+1, dirs->n_col-1);
199 if (n != 0) {
200 int pos = isl_seq_first_non_zero(dirs->row[n]+1, dirs->n_col-1);
201 if (pos < 0)
202 return 0;
203 for (i = 0; i < n; ++i) {
204 int pos_i;
205 pos_i = isl_seq_first_non_zero(dirs->row[i]+1, dirs->n_col-1);
206 if (pos_i < pos)
207 continue;
208 if (pos_i > pos)
209 break;
210 isl_seq_elim(dirs->row[n]+1, dirs->row[i]+1, pos,
211 dirs->n_col-1, NULL);
212 pos = isl_seq_first_non_zero(dirs->row[n]+1, dirs->n_col-1);
213 if (pos < 0)
214 return 0;
218 isl_seq_neg(dirs->row[n] + 1, dirs->row[n] + 1, dirs->n_col - 1);
219 is_bound = uset_is_bound(ctx, set, dirs->row[n], dirs->n_col);
220 isl_seq_neg(dirs->row[n] + 1, dirs->row[n] + 1, dirs->n_col - 1);
221 if (is_bound != 1)
222 return is_bound;
223 is_bound = uset_is_bound(ctx, set, dirs->row[n], dirs->n_col);
224 if (is_bound != 1)
225 return is_bound;
226 if (i < n) {
227 int k;
228 isl_int *t = dirs->row[n];
229 for (k = n; k > i; --k)
230 dirs->row[k] = dirs->row[k-1];
231 dirs->row[i] = t;
233 return 1;
236 /* Compute and return a maximal set of linearly independent bounds
237 * on the set "set", based on the constraints of the basic sets
238 * in "set".
240 static struct isl_mat *independent_bounds(struct isl_ctx *ctx,
241 struct isl_set *set)
243 int i, j, n;
244 struct isl_mat *dirs = NULL;
245 unsigned dim = isl_set_n_dim(set);
247 dirs = isl_mat_alloc(ctx, dim, 1+dim);
248 if (!dirs)
249 goto error;
251 n = 0;
252 for (i = 0; n < dim && i < set->n; ++i) {
253 int f;
254 struct isl_basic_set *bset = set->p[i];
256 for (j = 0; n < dim && j < bset->n_eq; ++j) {
257 f = is_independent_bound(ctx, set, bset->eq[j],
258 dirs, n);
259 if (f < 0)
260 goto error;
261 if (f)
262 ++n;
264 for (j = 0; n < dim && j < bset->n_ineq; ++j) {
265 f = is_independent_bound(ctx, set, bset->ineq[j],
266 dirs, n);
267 if (f < 0)
268 goto error;
269 if (f)
270 ++n;
273 dirs->n_row = n;
274 return dirs;
275 error:
276 isl_mat_free(ctx, dirs);
277 return NULL;
280 static struct isl_basic_set *isl_basic_set_set_rational(
281 struct isl_basic_set *bset)
283 if (!bset)
284 return NULL;
286 if (F_ISSET(bset, ISL_BASIC_MAP_RATIONAL))
287 return bset;
289 bset = isl_basic_set_cow(bset);
290 if (!bset)
291 return NULL;
293 F_SET(bset, ISL_BASIC_MAP_RATIONAL);
295 return isl_basic_set_finalize(bset);
298 static struct isl_set *isl_set_set_rational(struct isl_set *set)
300 int i;
302 set = isl_set_cow(set);
303 if (!set)
304 return NULL;
305 for (i = 0; i < set->n; ++i) {
306 set->p[i] = isl_basic_set_set_rational(set->p[i]);
307 if (!set->p[i])
308 goto error;
310 return set;
311 error:
312 isl_set_free(set);
313 return NULL;
316 static struct isl_basic_set *isl_basic_set_add_equality(struct isl_ctx *ctx,
317 struct isl_basic_set *bset, isl_int *c)
319 int i;
320 unsigned total;
321 unsigned dim;
323 if (F_ISSET(bset, ISL_BASIC_SET_EMPTY))
324 return bset;
326 isl_assert(ctx, isl_basic_set_n_param(bset) == 0, goto error);
327 isl_assert(ctx, bset->n_div == 0, goto error);
328 dim = isl_basic_set_n_dim(bset);
329 bset = isl_basic_set_extend(bset, 0, dim, 0, 1, 0);
330 i = isl_basic_set_alloc_equality(bset);
331 if (i < 0)
332 goto error;
333 isl_seq_cpy(bset->eq[i], c, 1 + dim);
334 return bset;
335 error:
336 isl_basic_set_free(bset);
337 return NULL;
340 static struct isl_set *isl_set_add_equality(struct isl_ctx *ctx,
341 struct isl_set *set, isl_int *c)
343 int i;
345 set = isl_set_cow(set);
346 if (!set)
347 return NULL;
348 for (i = 0; i < set->n; ++i) {
349 set->p[i] = isl_basic_set_add_equality(ctx, set->p[i], c);
350 if (!set->p[i])
351 goto error;
353 return set;
354 error:
355 isl_set_free(set);
356 return NULL;
359 /* Given a union of basic sets, construct the constraints for wrapping
360 * a facet around one of its ridges.
361 * In particular, if each of n the d-dimensional basic sets i in "set"
362 * contains the origin, satisfies the constraints x_1 >= 0 and x_2 >= 0
363 * and is defined by the constraints
364 * [ 1 ]
365 * A_i [ x ] >= 0
367 * then the resulting set is of dimension n*(1+d) and has as contraints
369 * [ a_i ]
370 * A_i [ x_i ] >= 0
372 * a_i >= 0
374 * \sum_i x_{i,1} = 1
376 static struct isl_basic_set *wrap_constraints(struct isl_ctx *ctx,
377 struct isl_set *set)
379 struct isl_basic_set *lp;
380 unsigned n_eq;
381 unsigned n_ineq;
382 int i, j, k;
383 unsigned dim, lp_dim;
385 if (!set)
386 return NULL;
388 dim = 1 + isl_set_n_dim(set);
389 n_eq = 1;
390 n_ineq = set->n;
391 for (i = 0; i < set->n; ++i) {
392 n_eq += set->p[i]->n_eq;
393 n_ineq += set->p[i]->n_ineq;
395 lp = isl_basic_set_alloc(ctx, 0, dim * set->n, 0, n_eq, n_ineq);
396 if (!lp)
397 return NULL;
398 lp_dim = isl_basic_set_n_dim(lp);
399 k = isl_basic_set_alloc_equality(lp);
400 isl_int_set_si(lp->eq[k][0], -1);
401 for (i = 0; i < set->n; ++i) {
402 isl_int_set_si(lp->eq[k][1+dim*i], 0);
403 isl_int_set_si(lp->eq[k][1+dim*i+1], 1);
404 isl_seq_clr(lp->eq[k]+1+dim*i+2, dim-2);
406 for (i = 0; i < set->n; ++i) {
407 k = isl_basic_set_alloc_inequality(lp);
408 isl_seq_clr(lp->ineq[k], 1+lp_dim);
409 isl_int_set_si(lp->ineq[k][1+dim*i], 1);
411 for (j = 0; j < set->p[i]->n_eq; ++j) {
412 k = isl_basic_set_alloc_equality(lp);
413 isl_seq_clr(lp->eq[k], 1+dim*i);
414 isl_seq_cpy(lp->eq[k]+1+dim*i, set->p[i]->eq[j], dim);
415 isl_seq_clr(lp->eq[k]+1+dim*(i+1), dim*(set->n-i-1));
418 for (j = 0; j < set->p[i]->n_ineq; ++j) {
419 k = isl_basic_set_alloc_inequality(lp);
420 isl_seq_clr(lp->ineq[k], 1+dim*i);
421 isl_seq_cpy(lp->ineq[k]+1+dim*i, set->p[i]->ineq[j], dim);
422 isl_seq_clr(lp->ineq[k]+1+dim*(i+1), dim*(set->n-i-1));
425 return lp;
428 /* Given a facet "facet" of the convex hull of "set" and a facet "ridge"
429 * of that facet, compute the other facet of the convex hull that contains
430 * the ridge.
432 * We first transform the set such that the facet constraint becomes
434 * x_1 >= 0
436 * I.e., the facet lies in
438 * x_1 = 0
440 * and on that facet, the constraint that defines the ridge is
442 * x_2 >= 0
444 * (This transformation is not strictly needed, all that is needed is
445 * that the ridge contains the origin.)
447 * Since the ridge contains the origin, the cone of the convex hull
448 * will be of the form
450 * x_1 >= 0
451 * x_2 >= a x_1
453 * with this second constraint defining the new facet.
454 * The constant a is obtained by settting x_1 in the cone of the
455 * convex hull to 1 and minimizing x_2.
456 * Now, each element in the cone of the convex hull is the sum
457 * of elements in the cones of the basic sets.
458 * If a_i is the dilation factor of basic set i, then the problem
459 * we need to solve is
461 * min \sum_i x_{i,2}
462 * st
463 * \sum_i x_{i,1} = 1
464 * a_i >= 0
465 * [ a_i ]
466 * A [ x_i ] >= 0
468 * with
469 * [ 1 ]
470 * A_i [ x_i ] >= 0
472 * the constraints of each (transformed) basic set.
473 * If a = n/d, then the constraint defining the new facet (in the transformed
474 * space) is
476 * -n x_1 + d x_2 >= 0
478 * In the original space, we need to take the same combination of the
479 * corresponding constraints "facet" and "ridge".
481 * If a = -infty = "-1/0", then we just return the original facet constraint.
482 * This means that the facet is unbounded, but has a bounded intersection
483 * with the union of sets.
485 static isl_int *wrap_facet(struct isl_ctx *ctx, struct isl_set *set,
486 isl_int *facet, isl_int *ridge)
488 int i;
489 struct isl_mat *T = NULL;
490 struct isl_basic_set *lp = NULL;
491 struct isl_vec *obj;
492 enum isl_lp_result res;
493 isl_int num, den;
494 unsigned dim;
496 set = isl_set_copy(set);
498 dim = 1 + isl_set_n_dim(set);
499 T = isl_mat_alloc(ctx, 3, dim);
500 if (!T)
501 goto error;
502 isl_int_set_si(T->row[0][0], 1);
503 isl_seq_clr(T->row[0]+1, dim - 1);
504 isl_seq_cpy(T->row[1], facet, dim);
505 isl_seq_cpy(T->row[2], ridge, dim);
506 T = isl_mat_right_inverse(ctx, T);
507 set = isl_set_preimage(ctx, set, T);
508 T = NULL;
509 if (!set)
510 goto error;
511 lp = wrap_constraints(ctx, set);
512 obj = isl_vec_alloc(ctx, dim*set->n);
513 if (!obj)
514 goto error;
515 for (i = 0; i < set->n; ++i) {
516 isl_seq_clr(obj->block.data+dim*i, 2);
517 isl_int_set_si(obj->block.data[dim*i+2], 1);
518 isl_seq_clr(obj->block.data+dim*i+3, dim-3);
520 isl_int_init(num);
521 isl_int_init(den);
522 res = isl_solve_lp((struct isl_basic_map *)lp, 0,
523 obj->block.data, ctx->one, &num, &den);
524 if (res == isl_lp_ok) {
525 isl_int_neg(num, num);
526 isl_seq_combine(facet, num, facet, den, ridge, dim);
528 isl_int_clear(num);
529 isl_int_clear(den);
530 isl_vec_free(ctx, obj);
531 isl_basic_set_free(lp);
532 isl_set_free(set);
533 isl_assert(ctx, res == isl_lp_ok || res == isl_lp_unbounded,
534 return NULL);
535 return facet;
536 error:
537 isl_basic_set_free(lp);
538 isl_mat_free(ctx, T);
539 isl_set_free(set);
540 return NULL;
543 /* Given a set of d linearly independent bounding constraints of the
544 * convex hull of "set", compute the constraint of a facet of "set".
546 * We first compute the intersection with the first bounding hyperplane
547 * and remove the component corresponding to this hyperplane from
548 * other bounds (in homogeneous space).
549 * We then wrap around one of the remaining bounding constraints
550 * and continue the process until all bounding constraints have been
551 * taken into account.
552 * The resulting linear combination of the bounding constraints will
553 * correspond to a facet of the convex hull.
555 static struct isl_mat *initial_facet_constraint(struct isl_ctx *ctx,
556 struct isl_set *set, struct isl_mat *bounds)
558 struct isl_set *slice = NULL;
559 struct isl_basic_set *face = NULL;
560 struct isl_mat *m, *U, *Q;
561 int i;
562 unsigned dim = isl_set_n_dim(set);
564 isl_assert(ctx, set->n > 0, goto error);
565 isl_assert(ctx, bounds->n_row == dim, goto error);
567 while (bounds->n_row > 1) {
568 slice = isl_set_copy(set);
569 slice = isl_set_add_equality(ctx, slice, bounds->row[0]);
570 face = isl_set_affine_hull(slice);
571 if (!face)
572 goto error;
573 if (face->n_eq == 1) {
574 isl_basic_set_free(face);
575 break;
577 m = isl_mat_alloc(ctx, 1 + face->n_eq, 1 + dim);
578 if (!m)
579 goto error;
580 isl_int_set_si(m->row[0][0], 1);
581 isl_seq_clr(m->row[0]+1, dim);
582 for (i = 0; i < face->n_eq; ++i)
583 isl_seq_cpy(m->row[1 + i], face->eq[i], 1 + dim);
584 U = isl_mat_right_inverse(ctx, m);
585 Q = isl_mat_right_inverse(ctx, isl_mat_copy(ctx, U));
586 U = isl_mat_drop_cols(ctx, U, 1 + face->n_eq,
587 dim - face->n_eq);
588 Q = isl_mat_drop_rows(ctx, Q, 1 + face->n_eq,
589 dim - face->n_eq);
590 U = isl_mat_drop_cols(ctx, U, 0, 1);
591 Q = isl_mat_drop_rows(ctx, Q, 0, 1);
592 bounds = isl_mat_product(ctx, bounds, U);
593 bounds = isl_mat_product(ctx, bounds, Q);
594 while (isl_seq_first_non_zero(bounds->row[bounds->n_row-1],
595 bounds->n_col) == -1) {
596 bounds->n_row--;
597 isl_assert(ctx, bounds->n_row > 1, goto error);
599 if (!wrap_facet(ctx, set, bounds->row[0],
600 bounds->row[bounds->n_row-1]))
601 goto error;
602 isl_basic_set_free(face);
603 bounds->n_row--;
605 return bounds;
606 error:
607 isl_basic_set_free(face);
608 isl_mat_free(ctx, bounds);
609 return NULL;
612 /* Given the bounding constraint "c" of a facet of the convex hull of "set",
613 * compute a hyperplane description of the facet, i.e., compute the facets
614 * of the facet.
616 * We compute an affine transformation that transforms the constraint
618 * [ 1 ]
619 * c [ x ] = 0
621 * to the constraint
623 * z_1 = 0
625 * by computing the right inverse U of a matrix that starts with the rows
627 * [ 1 0 ]
628 * [ c ]
630 * Then
631 * [ 1 ] [ 1 ]
632 * [ x ] = U [ z ]
633 * and
634 * [ 1 ] [ 1 ]
635 * [ z ] = Q [ x ]
637 * with Q = U^{-1}
638 * Since z_1 is zero, we can drop this variable as well as the corresponding
639 * column of U to obtain
641 * [ 1 ] [ 1 ]
642 * [ x ] = U' [ z' ]
643 * and
644 * [ 1 ] [ 1 ]
645 * [ z' ] = Q' [ x ]
647 * with Q' equal to Q, but without the corresponding row.
648 * After computing the facets of the facet in the z' space,
649 * we convert them back to the x space through Q.
651 static struct isl_basic_set *compute_facet(struct isl_ctx *ctx,
652 struct isl_set *set, isl_int *c)
654 struct isl_mat *m, *U, *Q;
655 struct isl_basic_set *facet;
656 unsigned dim;
658 set = isl_set_copy(set);
659 dim = isl_set_n_dim(set);
660 m = isl_mat_alloc(ctx, 2, 1 + dim);
661 if (!m)
662 goto error;
663 isl_int_set_si(m->row[0][0], 1);
664 isl_seq_clr(m->row[0]+1, dim);
665 isl_seq_cpy(m->row[1], c, 1+dim);
666 U = isl_mat_right_inverse(ctx, m);
667 Q = isl_mat_right_inverse(ctx, isl_mat_copy(ctx, U));
668 U = isl_mat_drop_cols(ctx, U, 1, 1);
669 Q = isl_mat_drop_rows(ctx, Q, 1, 1);
670 set = isl_set_preimage(ctx, set, U);
671 facet = uset_convex_hull_wrap(set);
672 facet = isl_basic_set_preimage(ctx, facet, Q);
673 return facet;
674 error:
675 isl_set_free(set);
676 return NULL;
679 /* Given an initial facet constraint, compute the remaining facets.
680 * We do this by running through all facets found so far and computing
681 * the adjacent facets through wrapping, adding those facets that we
682 * hadn't already found before.
684 * This function can still be significantly optimized by checking which of
685 * the facets of the basic sets are also facets of the convex hull and
686 * using all the facets so far to help in constructing the facets of the
687 * facets
688 * and/or
689 * using the technique in section "3.1 Ridge Generation" of
690 * "Extended Convex Hull" by Fukuda et al.
692 static struct isl_basic_set *extend(struct isl_ctx *ctx, struct isl_set *set,
693 struct isl_mat *initial)
695 int i, j, f;
696 int k;
697 struct isl_basic_set *hull = NULL;
698 struct isl_basic_set *facet = NULL;
699 unsigned n_ineq;
700 unsigned total;
701 unsigned dim;
703 isl_assert(ctx, set->n > 0, goto error);
705 n_ineq = 1;
706 for (i = 0; i < set->n; ++i) {
707 n_ineq += set->p[i]->n_eq;
708 n_ineq += set->p[i]->n_ineq;
710 dim = isl_set_n_dim(set);
711 isl_assert(ctx, 1 + dim == initial->n_col, goto error);
712 hull = isl_basic_set_alloc(ctx, 0, dim, 0, 0, n_ineq);
713 hull = isl_basic_set_set_rational(hull);
714 if (!hull)
715 goto error;
716 k = isl_basic_set_alloc_inequality(hull);
717 if (k < 0)
718 goto error;
719 isl_seq_cpy(hull->ineq[k], initial->row[0], initial->n_col);
720 for (i = 0; i < hull->n_ineq; ++i) {
721 facet = compute_facet(ctx, set, hull->ineq[i]);
722 if (!facet)
723 goto error;
724 if (facet->n_ineq + hull->n_ineq > n_ineq) {
725 hull = isl_basic_set_extend(hull,
726 0, dim, 0, 0, facet->n_ineq);
727 n_ineq = hull->n_ineq + facet->n_ineq;
729 for (j = 0; j < facet->n_ineq; ++j) {
730 k = isl_basic_set_alloc_inequality(hull);
731 if (k < 0)
732 goto error;
733 isl_seq_cpy(hull->ineq[k], hull->ineq[i], 1+dim);
734 if (!wrap_facet(ctx, set, hull->ineq[k], facet->ineq[j]))
735 goto error;
736 for (f = 0; f < k; ++f)
737 if (isl_seq_eq(hull->ineq[f], hull->ineq[k],
738 1+dim))
739 break;
740 if (f < k)
741 isl_basic_set_free_inequality(hull, 1);
743 isl_basic_set_free(facet);
745 hull = isl_basic_set_simplify(hull);
746 hull = isl_basic_set_finalize(hull);
747 return hull;
748 error:
749 isl_basic_set_free(facet);
750 isl_basic_set_free(hull);
751 return NULL;
754 /* Special case for computing the convex hull of a one dimensional set.
755 * We simply collect the lower and upper bounds of each basic set
756 * and the biggest of those.
758 static struct isl_basic_set *convex_hull_1d(struct isl_ctx *ctx,
759 struct isl_set *set)
761 struct isl_mat *c = NULL;
762 isl_int *lower = NULL;
763 isl_int *upper = NULL;
764 int i, j, k;
765 isl_int a, b;
766 struct isl_basic_set *hull;
768 for (i = 0; i < set->n; ++i) {
769 set->p[i] = isl_basic_set_simplify(set->p[i]);
770 if (!set->p[i])
771 goto error;
773 set = isl_set_remove_empty_parts(set);
774 if (!set)
775 goto error;
776 isl_assert(ctx, set->n > 0, goto error);
777 c = isl_mat_alloc(ctx, 2, 2);
778 if (!c)
779 goto error;
781 if (set->p[0]->n_eq > 0) {
782 isl_assert(ctx, set->p[0]->n_eq == 1, goto error);
783 lower = c->row[0];
784 upper = c->row[1];
785 if (isl_int_is_pos(set->p[0]->eq[0][1])) {
786 isl_seq_cpy(lower, set->p[0]->eq[0], 2);
787 isl_seq_neg(upper, set->p[0]->eq[0], 2);
788 } else {
789 isl_seq_neg(lower, set->p[0]->eq[0], 2);
790 isl_seq_cpy(upper, set->p[0]->eq[0], 2);
792 } else {
793 for (j = 0; j < set->p[0]->n_ineq; ++j) {
794 if (isl_int_is_pos(set->p[0]->ineq[j][1])) {
795 lower = c->row[0];
796 isl_seq_cpy(lower, set->p[0]->ineq[j], 2);
797 } else {
798 upper = c->row[1];
799 isl_seq_cpy(upper, set->p[0]->ineq[j], 2);
804 isl_int_init(a);
805 isl_int_init(b);
806 for (i = 0; i < set->n; ++i) {
807 struct isl_basic_set *bset = set->p[i];
808 int has_lower = 0;
809 int has_upper = 0;
811 for (j = 0; j < bset->n_eq; ++j) {
812 has_lower = 1;
813 has_upper = 1;
814 if (lower) {
815 isl_int_mul(a, lower[0], bset->eq[j][1]);
816 isl_int_mul(b, lower[1], bset->eq[j][0]);
817 if (isl_int_lt(a, b) && isl_int_is_pos(bset->eq[j][1]))
818 isl_seq_cpy(lower, bset->eq[j], 2);
819 if (isl_int_gt(a, b) && isl_int_is_neg(bset->eq[j][1]))
820 isl_seq_neg(lower, bset->eq[j], 2);
822 if (upper) {
823 isl_int_mul(a, upper[0], bset->eq[j][1]);
824 isl_int_mul(b, upper[1], bset->eq[j][0]);
825 if (isl_int_lt(a, b) && isl_int_is_pos(bset->eq[j][1]))
826 isl_seq_neg(upper, bset->eq[j], 2);
827 if (isl_int_gt(a, b) && isl_int_is_neg(bset->eq[j][1]))
828 isl_seq_cpy(upper, bset->eq[j], 2);
831 for (j = 0; j < bset->n_ineq; ++j) {
832 if (isl_int_is_pos(bset->ineq[j][1]))
833 has_lower = 1;
834 if (isl_int_is_neg(bset->ineq[j][1]))
835 has_upper = 1;
836 if (lower && isl_int_is_pos(bset->ineq[j][1])) {
837 isl_int_mul(a, lower[0], bset->ineq[j][1]);
838 isl_int_mul(b, lower[1], bset->ineq[j][0]);
839 if (isl_int_lt(a, b))
840 isl_seq_cpy(lower, bset->ineq[j], 2);
842 if (upper && isl_int_is_neg(bset->ineq[j][1])) {
843 isl_int_mul(a, upper[0], bset->ineq[j][1]);
844 isl_int_mul(b, upper[1], bset->ineq[j][0]);
845 if (isl_int_gt(a, b))
846 isl_seq_cpy(upper, bset->ineq[j], 2);
849 if (!has_lower)
850 lower = NULL;
851 if (!has_upper)
852 upper = NULL;
854 isl_int_clear(a);
855 isl_int_clear(b);
857 hull = isl_basic_set_alloc(ctx, 0, 1, 0, 0, 2);
858 hull = isl_basic_set_set_rational(hull);
859 if (!hull)
860 goto error;
861 if (lower) {
862 k = isl_basic_set_alloc_inequality(hull);
863 isl_seq_cpy(hull->ineq[k], lower, 2);
865 if (upper) {
866 k = isl_basic_set_alloc_inequality(hull);
867 isl_seq_cpy(hull->ineq[k], upper, 2);
869 hull = isl_basic_set_finalize(hull);
870 isl_set_free(set);
871 isl_mat_free(ctx, c);
872 return hull;
873 error:
874 isl_set_free(set);
875 isl_mat_free(ctx, c);
876 return NULL;
879 /* Project out final n dimensions using Fourier-Motzkin */
880 static struct isl_set *set_project_out(struct isl_ctx *ctx,
881 struct isl_set *set, unsigned n)
883 return isl_set_remove_dims(set, isl_set_n_dim(set) - n, n);
886 static struct isl_basic_set *convex_hull_0d(struct isl_set *set)
888 struct isl_basic_set *convex_hull;
890 if (!set)
891 return NULL;
893 if (isl_set_is_empty(set))
894 convex_hull = isl_basic_set_empty(isl_dim_copy(set->dim));
895 else
896 convex_hull = isl_basic_set_universe(isl_dim_copy(set->dim));
897 isl_set_free(set);
898 return convex_hull;
901 /* Compute the convex hull of a pair of basic sets without any parameters or
902 * integer divisions using Fourier-Motzkin elimination.
903 * The convex hull is the set of all points that can be written as
904 * the sum of points from both basic sets (in homogeneous coordinates).
905 * We set up the constraints in a space with dimensions for each of
906 * the three sets and then project out the dimensions corresponding
907 * to the two original basic sets, retaining only those corresponding
908 * to the convex hull.
910 static struct isl_basic_set *convex_hull_pair(struct isl_basic_set *bset1,
911 struct isl_basic_set *bset2)
913 int i, j, k;
914 struct isl_basic_set *bset[2];
915 struct isl_basic_set *hull = NULL;
916 unsigned dim;
918 if (!bset1 || !bset2)
919 goto error;
921 dim = isl_basic_set_n_dim(bset1);
922 hull = isl_basic_set_alloc(bset1->ctx, 0, 2 + 3 * dim, 0,
923 1 + dim + bset1->n_eq + bset2->n_eq,
924 2 + bset1->n_ineq + bset2->n_ineq);
925 bset[0] = bset1;
926 bset[1] = bset2;
927 for (i = 0; i < 2; ++i) {
928 for (j = 0; j < bset[i]->n_eq; ++j) {
929 k = isl_basic_set_alloc_equality(hull);
930 if (k < 0)
931 goto error;
932 isl_seq_clr(hull->eq[k], (i+1) * (1+dim));
933 isl_seq_clr(hull->eq[k]+(i+2)*(1+dim), (1-i)*(1+dim));
934 isl_seq_cpy(hull->eq[k]+(i+1)*(1+dim), bset[i]->eq[j],
935 1+dim);
937 for (j = 0; j < bset[i]->n_ineq; ++j) {
938 k = isl_basic_set_alloc_inequality(hull);
939 if (k < 0)
940 goto error;
941 isl_seq_clr(hull->ineq[k], (i+1) * (1+dim));
942 isl_seq_clr(hull->ineq[k]+(i+2)*(1+dim), (1-i)*(1+dim));
943 isl_seq_cpy(hull->ineq[k]+(i+1)*(1+dim),
944 bset[i]->ineq[j], 1+dim);
946 k = isl_basic_set_alloc_inequality(hull);
947 if (k < 0)
948 goto error;
949 isl_seq_clr(hull->ineq[k], 1+2+3*dim);
950 isl_int_set_si(hull->ineq[k][(i+1)*(1+dim)], 1);
952 for (j = 0; j < 1+dim; ++j) {
953 k = isl_basic_set_alloc_equality(hull);
954 if (k < 0)
955 goto error;
956 isl_seq_clr(hull->eq[k], 1+2+3*dim);
957 isl_int_set_si(hull->eq[k][j], -1);
958 isl_int_set_si(hull->eq[k][1+dim+j], 1);
959 isl_int_set_si(hull->eq[k][2*(1+dim)+j], 1);
961 hull = isl_basic_set_set_rational(hull);
962 hull = isl_basic_set_remove_dims(hull, dim, 2*(1+dim));
963 hull = isl_basic_set_convex_hull(hull);
964 isl_basic_set_free(bset1);
965 isl_basic_set_free(bset2);
966 return hull;
967 error:
968 isl_basic_set_free(bset1);
969 isl_basic_set_free(bset2);
970 isl_basic_set_free(hull);
971 return NULL;
974 /* Compute the convex hull of a set without any parameters or
975 * integer divisions using Fourier-Motzkin elimination.
976 * In each step, we combined two basic sets until only one
977 * basic set is left.
979 static struct isl_basic_set *uset_convex_hull_elim(struct isl_set *set)
981 struct isl_basic_set *convex_hull = NULL;
983 convex_hull = isl_set_copy_basic_set(set);
984 set = isl_set_drop_basic_set(set, convex_hull);
985 if (!set)
986 goto error;
987 while (set->n > 0) {
988 struct isl_basic_set *t;
989 t = isl_set_copy_basic_set(set);
990 if (!t)
991 goto error;
992 set = isl_set_drop_basic_set(set, t);
993 if (!set)
994 goto error;
995 convex_hull = convex_hull_pair(convex_hull, t);
997 isl_set_free(set);
998 return convex_hull;
999 error:
1000 isl_set_free(set);
1001 isl_basic_set_free(convex_hull);
1002 return NULL;
1005 static struct isl_basic_set *uset_convex_hull_wrap_with_bounds(
1006 struct isl_set *set, struct isl_mat *bounds)
1008 struct isl_basic_set *convex_hull = NULL;
1010 isl_assert(set->ctx, bounds->n_row == isl_set_n_dim(set), goto error);
1011 bounds = initial_facet_constraint(set->ctx, set, bounds);
1012 if (!bounds)
1013 goto error;
1014 convex_hull = extend(set->ctx, set, bounds);
1015 isl_mat_free(set->ctx, bounds);
1016 isl_set_free(set);
1018 return convex_hull;
1019 error:
1020 isl_set_free(set);
1021 return NULL;
1024 /* Compute the convex hull of a set without any parameters or
1025 * integer divisions. Depending on whether the set is bounded,
1026 * we pass control to the wrapping based convex hull or
1027 * the Fourier-Motzkin elimination based convex hull.
1028 * We also handle a few special cases before checking the boundedness.
1030 static struct isl_basic_set *uset_convex_hull(struct isl_set *set)
1032 int i;
1033 struct isl_basic_set *convex_hull = NULL;
1034 struct isl_mat *bounds;
1036 if (isl_set_n_dim(set) == 0)
1037 return convex_hull_0d(set);
1039 set = isl_set_set_rational(set);
1041 if (!set)
1042 goto error;
1043 for (i = 0; i < set->n; ++i) {
1044 set->p[i] = isl_basic_set_convex_hull(set->p[i]);
1045 if (!set->p[i])
1046 goto error;
1048 set = isl_set_remove_empty_parts(set);
1049 if (!set)
1050 return NULL;
1051 if (set->n == 1) {
1052 convex_hull = isl_basic_set_copy(set->p[0]);
1053 isl_set_free(set);
1054 return convex_hull;
1056 if (isl_set_n_dim(set) == 1)
1057 return convex_hull_1d(set->ctx, set);
1059 bounds = independent_bounds(set->ctx, set);
1060 if (!bounds)
1061 goto error;
1062 if (bounds->n_row == isl_set_n_dim(set))
1063 return uset_convex_hull_wrap_with_bounds(set, bounds);
1064 isl_mat_free(set->ctx, bounds);
1066 return uset_convex_hull_elim(set);
1067 error:
1068 isl_set_free(set);
1069 isl_basic_set_free(convex_hull);
1070 return NULL;
1073 /* This is the core procedure, where "set" is a "pure" set, i.e.,
1074 * without parameters or divs and where the convex hull of set is
1075 * known to be full-dimensional.
1077 static struct isl_basic_set *uset_convex_hull_wrap(struct isl_set *set)
1079 int i;
1080 struct isl_basic_set *convex_hull = NULL;
1081 struct isl_mat *bounds;
1083 if (isl_set_n_dim(set) == 0) {
1084 convex_hull = isl_basic_set_universe(isl_dim_copy(set->dim));
1085 isl_set_free(set);
1086 convex_hull = isl_basic_set_set_rational(convex_hull);
1087 return convex_hull;
1090 set = isl_set_set_rational(set);
1092 if (!set)
1093 goto error;
1094 for (i = 0; i < set->n; ++i) {
1095 set->p[i] = isl_basic_set_convex_hull(set->p[i]);
1096 if (!set->p[i])
1097 goto error;
1099 set = isl_set_remove_empty_parts(set);
1100 if (!set)
1101 goto error;
1102 if (set->n == 1) {
1103 convex_hull = isl_basic_set_copy(set->p[0]);
1104 isl_set_free(set);
1105 return convex_hull;
1107 if (isl_set_n_dim(set) == 1)
1108 return convex_hull_1d(set->ctx, set);
1110 bounds = independent_bounds(set->ctx, set);
1111 if (!bounds)
1112 goto error;
1113 return uset_convex_hull_wrap_with_bounds(set, bounds);
1114 error:
1115 isl_set_free(set);
1116 return NULL;
1119 /* Compute the convex hull of set "set" with affine hull "affine_hull",
1120 * We first remove the equalities (transforming the set), compute the
1121 * convex hull of the transformed set and then add the equalities back
1122 * (after performing the inverse transformation.
1124 static struct isl_basic_set *modulo_affine_hull(struct isl_ctx *ctx,
1125 struct isl_set *set, struct isl_basic_set *affine_hull)
1127 struct isl_mat *T;
1128 struct isl_mat *T2;
1129 struct isl_basic_set *dummy;
1130 struct isl_basic_set *convex_hull;
1132 dummy = isl_basic_set_remove_equalities(
1133 isl_basic_set_copy(affine_hull), &T, &T2);
1134 if (!dummy)
1135 goto error;
1136 isl_basic_set_free(dummy);
1137 set = isl_set_preimage(ctx, set, T);
1138 convex_hull = uset_convex_hull(set);
1139 convex_hull = isl_basic_set_preimage(ctx, convex_hull, T2);
1140 convex_hull = isl_basic_set_intersect(convex_hull, affine_hull);
1141 return convex_hull;
1142 error:
1143 isl_basic_set_free(affine_hull);
1144 isl_set_free(set);
1145 return NULL;
1148 /* Compute the convex hull of a map.
1150 * The implementation was inspired by "Extended Convex Hull" by Fukuda et al.,
1151 * specifically, the wrapping of facets to obtain new facets.
1153 struct isl_basic_map *isl_map_convex_hull(struct isl_map *map)
1155 struct isl_basic_set *bset;
1156 struct isl_basic_map *model = NULL;
1157 struct isl_basic_set *affine_hull = NULL;
1158 struct isl_basic_map *convex_hull = NULL;
1159 struct isl_set *set = NULL;
1160 struct isl_ctx *ctx;
1162 if (!map)
1163 goto error;
1165 ctx = map->ctx;
1166 if (map->n == 0) {
1167 convex_hull = isl_basic_map_empty_like_map(map);
1168 isl_map_free(map);
1169 return convex_hull;
1172 map = isl_map_align_divs(map);
1173 model = isl_basic_map_copy(map->p[0]);
1174 set = isl_map_underlying_set(map);
1175 if (!set)
1176 goto error;
1178 affine_hull = isl_set_affine_hull(isl_set_copy(set));
1179 if (!affine_hull)
1180 goto error;
1181 if (affine_hull->n_eq != 0)
1182 bset = modulo_affine_hull(ctx, set, affine_hull);
1183 else {
1184 isl_basic_set_free(affine_hull);
1185 bset = uset_convex_hull(set);
1188 convex_hull = isl_basic_map_overlying_set(bset, model);
1190 F_CLR(convex_hull, ISL_BASIC_MAP_RATIONAL);
1191 return convex_hull;
1192 error:
1193 isl_set_free(set);
1194 isl_basic_map_free(model);
1195 return NULL;
1198 struct isl_basic_set *isl_set_convex_hull(struct isl_set *set)
1200 return (struct isl_basic_set *)
1201 isl_map_convex_hull((struct isl_map *)set);
1204 /* Compute a superset of the convex hull of map that is described
1205 * by only translates of the constraints in the constituents of map.
1207 * The implementation is not very efficient. In particular, if
1208 * constraints with the same normal appear in more than one
1209 * basic map, they will be (re)examined each time.
1211 struct isl_basic_map *isl_map_simple_hull(struct isl_map *map)
1213 struct isl_set *set = NULL;
1214 struct isl_basic_map *model = NULL;
1215 struct isl_basic_map *hull;
1216 struct isl_basic_set *bset = NULL;
1217 int i, j;
1218 unsigned n_ineq;
1219 unsigned dim;
1221 if (!map)
1222 return NULL;
1223 if (map->n == 0) {
1224 hull = isl_basic_map_empty_like_map(map);
1225 isl_map_free(map);
1226 return hull;
1228 if (map->n == 1) {
1229 hull = isl_basic_map_copy(map->p[0]);
1230 isl_map_free(map);
1231 return hull;
1234 map = isl_map_align_divs(map);
1235 model = isl_basic_map_copy(map->p[0]);
1237 n_ineq = 0;
1238 for (i = 0; i < map->n; ++i) {
1239 if (!map->p[i])
1240 goto error;
1241 n_ineq += map->p[i]->n_ineq;
1244 set = isl_map_underlying_set(map);
1245 if (!set)
1246 goto error;
1248 bset = isl_set_affine_hull(isl_set_copy(set));
1249 if (!bset)
1250 goto error;
1251 dim = isl_basic_set_n_dim(bset);
1252 bset = isl_basic_set_extend(bset, 0, dim, 0, 0, n_ineq);
1253 if (!bset)
1254 goto error;
1256 for (i = 0; i < set->n; ++i) {
1257 for (j = 0; j < set->p[i]->n_ineq; ++j) {
1258 int k;
1259 int is_bound;
1261 k = isl_basic_set_alloc_inequality(bset);
1262 if (k < 0)
1263 goto error;
1264 isl_seq_cpy(bset->ineq[k], set->p[i]->ineq[j], 1 + dim);
1265 is_bound = uset_is_bound(set->ctx, set, bset->ineq[k],
1266 1 + dim);
1267 if (is_bound < 0)
1268 goto error;
1269 if (!is_bound)
1270 isl_basic_set_free_inequality(bset, 1);
1274 bset = isl_basic_set_simplify(bset);
1275 bset = isl_basic_set_finalize(bset);
1276 bset = isl_basic_set_convex_hull(bset);
1278 hull = isl_basic_map_overlying_set(bset, model);
1280 isl_set_free(set);
1281 return hull;
1282 error:
1283 isl_basic_set_free(bset);
1284 isl_set_free(set);
1285 isl_basic_map_free(model);
1286 return NULL;
1289 struct isl_basic_set *isl_set_simple_hull(struct isl_set *set)
1291 return (struct isl_basic_set *)
1292 isl_map_simple_hull((struct isl_map *)set);