1 /*
2 * Copyright 2008-2009 Katholieke Universiteit Leuven
3 * Copyright 2014 INRIA Rocquencourt
4 *
5 * Use of this software is governed by the MIT license
6 *
7 * Written by Sven Verdoolaege, K.U.Leuven, Departement
8 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
9 * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
10 * B.P. 105 - 78153 Le Chesnay, France
11 */
12
13 #include <isl_ctx_private.h>
14 #include <isl_map_private.h>
15 #include <isl_lp_private.h>
16 #include <isl/map.h>
17 #include <isl_mat_private.h>
18 #include <isl_vec_private.h>
19 #include <isl/set.h>
20 #include <isl_seq.h>
21 #include <isl_options_private.h>
22 #include "isl_equalities.h"
23 #include "isl_tab.h"
24 #include <isl_sort.h>
25
26 #include <bset_to_bmap.c>
27 #include <bset_from_bmap.c>
28 #include <set_to_map.c>
29
30 static __isl_give isl_basic_set *uset_convex_hull_wrap_bounded(
31 __isl_take isl_set *set);
32
33 /* Remove redundant
34 * constraints. If the minimal value along the normal of a constraint
35 * is the same if the constraint is removed, then the constraint is redundant.
36 *
37 * Since some constraints may be mutually redundant, sort the constraints
38 * first such that constraints that involve existentially quantified
39 * variables are considered for removal before those that do not.
40 * The sorting is also needed for the use in map_simple_hull.
41 *
42 * Note that isl_tab_detect_implicit_equalities may also end up
43 * marking some constraints as redundant. Make sure the constraints
44 * are preserved and undo those marking such that isl_tab_detect_redundant
45 * can consider the constraints in the sorted order.
46 *
47 * Alternatively, we could have intersected the basic map with the
48 * corresponding equality and then checked if the dimension was that
49 * of a facet.
50 */
isl_basic_map_remove_redundancies(__isl_take isl_basic_map * bmap)51 __isl_give isl_basic_map *isl_basic_map_remove_redundancies(
52 __isl_take isl_basic_map *bmap)
53 {
54 struct isl_tab *tab;
55
56 if (!bmap)
57 return NULL;
58
59 bmap = isl_basic_map_gauss(bmap, NULL);
60 if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
61 return bmap;
62 if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NO_REDUNDANT))
63 return bmap;
64 if (bmap->n_ineq <= 1)
65 return bmap;
66
67 bmap = isl_basic_map_sort_constraints(bmap);
68 tab = isl_tab_from_basic_map(bmap, 0);
69 if (!tab)
70 goto error;
71 tab->preserve = 1;
72 if (isl_tab_detect_implicit_equalities(tab) < 0)
73 goto error;
74 if (isl_tab_restore_redundant(tab) < 0)
75 goto error;
76 tab->preserve = 0;
77 if (isl_tab_detect_redundant(tab) < 0)
78 goto error;
79 bmap = isl_basic_map_update_from_tab(bmap, tab);
80 isl_tab_free(tab);
81 if (!bmap)
82 return NULL;
83 ISL_F_SET(bmap, ISL_BASIC_MAP_NO_IMPLICIT);
84 ISL_F_SET(bmap, ISL_BASIC_MAP_NO_REDUNDANT);
85 return bmap;
86 error:
87 isl_tab_free(tab);
88 isl_basic_map_free(bmap);
89 return NULL;
90 }
91
isl_basic_set_remove_redundancies(__isl_take isl_basic_set * bset)92 __isl_give isl_basic_set *isl_basic_set_remove_redundancies(
93 __isl_take isl_basic_set *bset)
94 {
95 return bset_from_bmap(
96 isl_basic_map_remove_redundancies(bset_to_bmap(bset)));
97 }
98
99 /* Remove redundant constraints in each of the basic maps.
100 */
isl_map_remove_redundancies(__isl_take isl_map * map)101 __isl_give isl_map *isl_map_remove_redundancies(__isl_take isl_map *map)
102 {
103 return isl_map_inline_foreach_basic_map(map,
104 &isl_basic_map_remove_redundancies);
105 }
106
isl_set_remove_redundancies(__isl_take isl_set * set)107 __isl_give isl_set *isl_set_remove_redundancies(__isl_take isl_set *set)
108 {
109 return isl_map_remove_redundancies(set);
110 }
111
112 /* Check if the set set is bound in the direction of the affine
113 * constraint c and if so, set the constant term such that the
114 * resulting constraint is a bounding constraint for the set.
115 */
uset_is_bound(__isl_keep isl_set * set,isl_int * c,unsigned len)116 static isl_bool uset_is_bound(__isl_keep isl_set *set, isl_int *c, unsigned len)
117 {
118 int first;
119 int j;
120 isl_int opt;
121 isl_int opt_denom;
122
123 isl_int_init(opt);
124 isl_int_init(opt_denom);
125 first = 1;
126 for (j = 0; j < set->n; ++j) {
127 enum isl_lp_result res;
128
129 if (ISL_F_ISSET(set->p[j], ISL_BASIC_SET_EMPTY))
130 continue;
131
132 res = isl_basic_set_solve_lp(set->p[j],
133 0, c, set->ctx->one, &opt, &opt_denom, NULL);
134 if (res == isl_lp_unbounded)
135 break;
136 if (res == isl_lp_error)
137 goto error;
138 if (res == isl_lp_empty) {
139 set->p[j] = isl_basic_set_set_to_empty(set->p[j]);
140 if (!set->p[j])
141 goto error;
142 continue;
143 }
144 if (first || isl_int_is_neg(opt)) {
145 if (!isl_int_is_one(opt_denom))
146 isl_seq_scale(c, c, opt_denom, len);
147 isl_int_sub(c[0], c[0], opt);
148 }
149 first = 0;
150 }
151 isl_int_clear(opt);
152 isl_int_clear(opt_denom);
153 return isl_bool_ok(j >= set->n);
154 error:
155 isl_int_clear(opt);
156 isl_int_clear(opt_denom);
157 return isl_bool_error;
158 }
159
isl_set_add_basic_set_equality(__isl_take isl_set * set,isl_int * c)160 static __isl_give isl_set *isl_set_add_basic_set_equality(
161 __isl_take isl_set *set, isl_int *c)
162 {
163 int i;
164
165 set = isl_set_cow(set);
166 if (!set)
167 return NULL;
168 for (i = 0; i < set->n; ++i) {
169 set->p[i] = isl_basic_set_add_eq(set->p[i], c);
170 if (!set->p[i])
171 goto error;
172 }
173 return set;
174 error:
175 isl_set_free(set);
176 return NULL;
177 }
178
179 /* Given a union of basic sets, construct the constraints for wrapping
180 * a facet around one of its ridges.
181 * In particular, if each of n the d-dimensional basic sets i in "set"
182 * contains the origin, satisfies the constraints x_1 >= 0 and x_2 >= 0
183 * and is defined by the constraints
184 * [ 1 ]
185 * A_i [ x ] >= 0
186 *
187 * then the resulting set is of dimension n*(1+d) and has as constraints
188 *
189 * [ a_i ]
190 * A_i [ x_i ] >= 0
191 *
192 * a_i >= 0
193 *
194 * \sum_i x_{i,1} = 1
195 */
wrap_constraints(__isl_keep isl_set * set)196 static __isl_give isl_basic_set *wrap_constraints(__isl_keep isl_set *set)
197 {
198 struct isl_basic_set *lp;
199 unsigned n_eq;
200 unsigned n_ineq;
201 int i, j, k;
202 isl_size dim, lp_dim;
203
204 dim = isl_set_dim(set, isl_dim_set);
205 if (dim < 0)
206 return NULL;
207
208 dim += 1;
209 n_eq = 1;
210 n_ineq = set->n;
211 for (i = 0; i < set->n; ++i) {
212 n_eq += set->p[i]->n_eq;
213 n_ineq += set->p[i]->n_ineq;
214 }
215 lp = isl_basic_set_alloc(set->ctx, 0, dim * set->n, 0, n_eq, n_ineq);
216 lp = isl_basic_set_set_rational(lp);
217 if (!lp)
218 return NULL;
219 lp_dim = isl_basic_set_dim(lp, isl_dim_set);
220 if (lp_dim < 0)
221 return isl_basic_set_free(lp);
222 k = isl_basic_set_alloc_equality(lp);
223 isl_int_set_si(lp->eq[k][0], -1);
224 for (i = 0; i < set->n; ++i) {
225 isl_int_set_si(lp->eq[k][1+dim*i], 0);
226 isl_int_set_si(lp->eq[k][1+dim*i+1], 1);
227 isl_seq_clr(lp->eq[k]+1+dim*i+2, dim-2);
228 }
229 for (i = 0; i < set->n; ++i) {
230 k = isl_basic_set_alloc_inequality(lp);
231 isl_seq_clr(lp->ineq[k], 1+lp_dim);
232 isl_int_set_si(lp->ineq[k][1+dim*i], 1);
233
234 for (j = 0; j < set->p[i]->n_eq; ++j) {
235 k = isl_basic_set_alloc_equality(lp);
236 isl_seq_clr(lp->eq[k], 1+dim*i);
237 isl_seq_cpy(lp->eq[k]+1+dim*i, set->p[i]->eq[j], dim);
238 isl_seq_clr(lp->eq[k]+1+dim*(i+1), dim*(set->n-i-1));
239 }
240
241 for (j = 0; j < set->p[i]->n_ineq; ++j) {
242 k = isl_basic_set_alloc_inequality(lp);
243 isl_seq_clr(lp->ineq[k], 1+dim*i);
244 isl_seq_cpy(lp->ineq[k]+1+dim*i, set->p[i]->ineq[j], dim);
245 isl_seq_clr(lp->ineq[k]+1+dim*(i+1), dim*(set->n-i-1));
246 }
247 }
248 return lp;
249 }
250
251 /* Given a facet "facet" of the convex hull of "set" and a facet "ridge"
252 * of that facet, compute the other facet of the convex hull that contains
253 * the ridge.
254 *
255 * We first transform the set such that the facet constraint becomes
256 *
257 * x_1 >= 0
258 *
259 * I.e., the facet lies in
260 *
261 * x_1 = 0
262 *
263 * and on that facet, the constraint that defines the ridge is
264 *
265 * x_2 >= 0
266 *
267 * (This transformation is not strictly needed, all that is needed is
268 * that the ridge contains the origin.)
269 *
270 * Since the ridge contains the origin, the cone of the convex hull
271 * will be of the form
272 *
273 * x_1 >= 0
274 * x_2 >= a x_1
275 *
276 * with this second constraint defining the new facet.
277 * The constant a is obtained by settting x_1 in the cone of the
278 * convex hull to 1 and minimizing x_2.
279 * Now, each element in the cone of the convex hull is the sum
280 * of elements in the cones of the basic sets.
281 * If a_i is the dilation factor of basic set i, then the problem
282 * we need to solve is
283 *
284 * min \sum_i x_{i,2}
285 * st
286 * \sum_i x_{i,1} = 1
287 * a_i >= 0
288 * [ a_i ]
289 * A [ x_i ] >= 0
290 *
291 * with
292 * [ 1 ]
293 * A_i [ x_i ] >= 0
294 *
295 * the constraints of each (transformed) basic set.
296 * If a = n/d, then the constraint defining the new facet (in the transformed
297 * space) is
298 *
299 * -n x_1 + d x_2 >= 0
300 *
301 * In the original space, we need to take the same combination of the
302 * corresponding constraints "facet" and "ridge".
303 *
304 * If a = -infty = "-1/0", then we just return the original facet constraint.
305 * This means that the facet is unbounded, but has a bounded intersection
306 * with the union of sets.
307 */
isl_set_wrap_facet(__isl_keep isl_set * set,isl_int * facet,isl_int * ridge)308 isl_int *isl_set_wrap_facet(__isl_keep isl_set *set,
309 isl_int *facet, isl_int *ridge)
310 {
311 int i;
312 isl_ctx *ctx;
313 struct isl_mat *T = NULL;
314 struct isl_basic_set *lp = NULL;
315 struct isl_vec *obj;
316 enum isl_lp_result res;
317 isl_int num, den;
318 isl_size dim;
319
320 dim = isl_set_dim(set, isl_dim_set);
321 if (dim < 0)
322 return NULL;
323 ctx = set->ctx;
324 set = isl_set_copy(set);
325 set = isl_set_set_rational(set);
326
327 dim += 1;
328 T = isl_mat_alloc(ctx, 3, dim);
329 if (!T)
330 goto error;
331 isl_int_set_si(T->row[0][0], 1);
332 isl_seq_clr(T->row[0]+1, dim - 1);
333 isl_seq_cpy(T->row[1], facet, dim);
334 isl_seq_cpy(T->row[2], ridge, dim);
335 T = isl_mat_right_inverse(T);
336 set = isl_set_preimage(set, T);
337 T = NULL;
338 if (!set)
339 goto error;
340 lp = wrap_constraints(set);
341 obj = isl_vec_alloc(ctx, 1 + dim*set->n);
342 if (!obj)
343 goto error;
344 isl_int_set_si(obj->block.data[0], 0);
345 for (i = 0; i < set->n; ++i) {
346 isl_seq_clr(obj->block.data + 1 + dim*i, 2);
347 isl_int_set_si(obj->block.data[1 + dim*i+2], 1);
348 isl_seq_clr(obj->block.data + 1 + dim*i+3, dim-3);
349 }
350 isl_int_init(num);
351 isl_int_init(den);
352 res = isl_basic_set_solve_lp(lp, 0,
353 obj->block.data, ctx->one, &num, &den, NULL);
354 if (res == isl_lp_ok) {
355 isl_int_neg(num, num);
356 isl_seq_combine(facet, num, facet, den, ridge, dim);
357 isl_seq_normalize(ctx, facet, dim);
358 }
359 isl_int_clear(num);
360 isl_int_clear(den);
361 isl_vec_free(obj);
362 isl_basic_set_free(lp);
363 isl_set_free(set);
364 if (res == isl_lp_error)
365 return NULL;
366 isl_assert(ctx, res == isl_lp_ok || res == isl_lp_unbounded,
367 return NULL);
368 return facet;
369 error:
370 isl_basic_set_free(lp);
371 isl_mat_free(T);
372 isl_set_free(set);
373 return NULL;
374 }
375
376 /* Compute the constraint of a facet of "set".
377 *
378 * We first compute the intersection with a bounding constraint
379 * that is orthogonal to one of the coordinate axes.
380 * If the affine hull of this intersection has only one equality,
381 * we have found a facet.
382 * Otherwise, we wrap the current bounding constraint around
383 * one of the equalities of the face (one that is not equal to
384 * the current bounding constraint).
385 * This process continues until we have found a facet.
386 * The dimension of the intersection increases by at least
387 * one on each iteration, so termination is guaranteed.
388 */
initial_facet_constraint(__isl_keep isl_set * set)389 static __isl_give isl_mat *initial_facet_constraint(__isl_keep isl_set *set)
390 {
391 struct isl_set *slice = NULL;
392 struct isl_basic_set *face = NULL;
393 int i;
394 isl_size dim = isl_set_dim(set, isl_dim_set);
395 isl_bool is_bound;
396 isl_mat *bounds = NULL;
397
398 if (dim < 0)
399 return NULL;
400 isl_assert(set->ctx, set->n > 0, goto error);
401 bounds = isl_mat_alloc(set->ctx, 1, 1 + dim);
402 if (!bounds)
403 return NULL;
404
405 isl_seq_clr(bounds->row[0], dim);
406 isl_int_set_si(bounds->row[0][1 + dim - 1], 1);
407 is_bound = uset_is_bound(set, bounds->row[0], 1 + dim);
408 if (is_bound < 0)
409 goto error;
410 isl_assert(set->ctx, is_bound, goto error);
411 isl_seq_normalize(set->ctx, bounds->row[0], 1 + dim);
412 bounds->n_row = 1;
413
414 for (;;) {
415 slice = isl_set_copy(set);
416 slice = isl_set_add_basic_set_equality(slice, bounds->row[0]);
417 face = isl_set_affine_hull(slice);
418 if (!face)
419 goto error;
420 if (face->n_eq == 1) {
421 isl_basic_set_free(face);
422 break;
423 }
424 for (i = 0; i < face->n_eq; ++i)
425 if (!isl_seq_eq(bounds->row[0], face->eq[i], 1 + dim) &&
426 !isl_seq_is_neg(bounds->row[0],
427 face->eq[i], 1 + dim))
428 break;
429 isl_assert(set->ctx, i < face->n_eq, goto error);
430 if (!isl_set_wrap_facet(set, bounds->row[0], face->eq[i]))
431 goto error;
432 isl_seq_normalize(set->ctx, bounds->row[0], bounds->n_col);
433 isl_basic_set_free(face);
434 }
435
436 return bounds;
437 error:
438 isl_basic_set_free(face);
439 isl_mat_free(bounds);
440 return NULL;
441 }
442
443 /* Given the bounding constraint "c" of a facet of the convex hull of "set",
444 * compute a hyperplane description of the facet, i.e., compute the facets
445 * of the facet.
446 *
447 * We compute an affine transformation that transforms the constraint
448 *
449 * [ 1 ]
450 * c [ x ] = 0
451 *
452 * to the constraint
453 *
454 * z_1 = 0
455 *
456 * by computing the right inverse U of a matrix that starts with the rows
457 *
458 * [ 1 0 ]
459 * [ c ]
460 *
461 * Then
462 * [ 1 ] [ 1 ]
463 * [ x ] = U [ z ]
464 * and
465 * [ 1 ] [ 1 ]
466 * [ z ] = Q [ x ]
467 *
468 * with Q = U^{-1}
469 * Since z_1 is zero, we can drop this variable as well as the corresponding
470 * column of U to obtain
471 *
472 * [ 1 ] [ 1 ]
473 * [ x ] = U' [ z' ]
474 * and
475 * [ 1 ] [ 1 ]
476 * [ z' ] = Q' [ x ]
477 *
478 * with Q' equal to Q, but without the corresponding row.
479 * After computing the facets of the facet in the z' space,
480 * we convert them back to the x space through Q.
481 */
compute_facet(__isl_keep isl_set * set,isl_int * c)482 static __isl_give isl_basic_set *compute_facet(__isl_keep isl_set *set,
483 isl_int *c)
484 {
485 struct isl_mat *m, *U, *Q;
486 struct isl_basic_set *facet = NULL;
487 struct isl_ctx *ctx;
488 isl_size dim;
489
490 dim = isl_set_dim(set, isl_dim_set);
491 if (dim < 0)
492 return NULL;
493 ctx = set->ctx;
494 set = isl_set_copy(set);
495 m = isl_mat_alloc(set->ctx, 2, 1 + dim);
496 if (!m)
497 goto error;
498 isl_int_set_si(m->row[0][0], 1);
499 isl_seq_clr(m->row[0]+1, dim);
500 isl_seq_cpy(m->row[1], c, 1+dim);
501 U = isl_mat_right_inverse(m);
502 Q = isl_mat_right_inverse(isl_mat_copy(U));
503 U = isl_mat_drop_cols(U, 1, 1);
504 Q = isl_mat_drop_rows(Q, 1, 1);
505 set = isl_set_preimage(set, U);
506 facet = uset_convex_hull_wrap_bounded(set);
507 facet = isl_basic_set_preimage(facet, Q);
508 if (facet && facet->n_eq != 0)
509 isl_die(ctx, isl_error_internal, "unexpected equality",
510 return isl_basic_set_free(facet));
511 return facet;
512 error:
513 isl_basic_set_free(facet);
514 isl_set_free(set);
515 return NULL;
516 }
517
518 /* Given an initial facet constraint, compute the remaining facets.
519 * We do this by running through all facets found so far and computing
520 * the adjacent facets through wrapping, adding those facets that we
521 * hadn't already found before.
522 *
523 * For each facet we have found so far, we first compute its facets
524 * in the resulting convex hull. That is, we compute the ridges
525 * of the resulting convex hull contained in the facet.
526 * We also compute the corresponding facet in the current approximation
527 * of the convex hull. There is no need to wrap around the ridges
528 * in this facet since that would result in a facet that is already
529 * present in the current approximation.
530 *
531 * This function can still be significantly optimized by checking which of
532 * the facets of the basic sets are also facets of the convex hull and
533 * using all the facets so far to help in constructing the facets of the
534 * facets
535 * and/or
536 * using the technique in section "3.1 Ridge Generation" of
537 * "Extended Convex Hull" by Fukuda et al.
538 */
extend(__isl_take isl_basic_set * hull,__isl_keep isl_set * set)539 static __isl_give isl_basic_set *extend(__isl_take isl_basic_set *hull,
540 __isl_keep isl_set *set)
541 {
542 int i, j, f;
543 int k;
544 struct isl_basic_set *facet = NULL;
545 struct isl_basic_set *hull_facet = NULL;
546 isl_size dim;
547
548 dim = isl_set_dim(set, isl_dim_set);
549 if (dim < 0 || !hull)
550 return isl_basic_set_free(hull);
551
552 isl_assert(set->ctx, set->n > 0, goto error);
553
554 for (i = 0; i < hull->n_ineq; ++i) {
555 facet = compute_facet(set, hull->ineq[i]);
556 facet = isl_basic_set_add_eq(facet, hull->ineq[i]);
557 facet = isl_basic_set_gauss(facet, NULL);
558 facet = isl_basic_set_normalize_constraints(facet);
559 hull_facet = isl_basic_set_copy(hull);
560 hull_facet = isl_basic_set_add_eq(hull_facet, hull->ineq[i]);
561 hull_facet = isl_basic_set_gauss(hull_facet, NULL);
562 hull_facet = isl_basic_set_normalize_constraints(hull_facet);
563 if (!facet || !hull_facet)
564 goto error;
565 hull = isl_basic_set_cow(hull);
566 hull = isl_basic_set_extend(hull, 0, 0, facet->n_ineq);
567 if (!hull)
568 goto error;
569 for (j = 0; j < facet->n_ineq; ++j) {
570 for (f = 0; f < hull_facet->n_ineq; ++f)
571 if (isl_seq_eq(facet->ineq[j],
572 hull_facet->ineq[f], 1 + dim))
573 break;
574 if (f < hull_facet->n_ineq)
575 continue;
576 k = isl_basic_set_alloc_inequality(hull);
577 if (k < 0)
578 goto error;
579 isl_seq_cpy(hull->ineq[k], hull->ineq[i], 1+dim);
580 if (!isl_set_wrap_facet(set, hull->ineq[k], facet->ineq[j]))
581 goto error;
582 }
583 isl_basic_set_free(hull_facet);
584 isl_basic_set_free(facet);
585 }
586 hull = isl_basic_set_simplify(hull);
587 hull = isl_basic_set_finalize(hull);
588 return hull;
589 error:
590 isl_basic_set_free(hull_facet);
591 isl_basic_set_free(facet);
592 isl_basic_set_free(hull);
593 return NULL;
594 }
595
596 /* Special case for computing the convex hull of a one dimensional set.
597 * We simply collect the lower and upper bounds of each basic set
598 * and the biggest of those.
599 */
convex_hull_1d(__isl_take isl_set * set)600 static __isl_give isl_basic_set *convex_hull_1d(__isl_take isl_set *set)
601 {
602 struct isl_mat *c = NULL;
603 isl_int *lower = NULL;
604 isl_int *upper = NULL;
605 int i, j, k;
606 isl_int a, b;
607 struct isl_basic_set *hull;
608
609 for (i = 0; i < set->n; ++i) {
610 set->p[i] = isl_basic_set_simplify(set->p[i]);
611 if (!set->p[i])
612 goto error;
613 }
614 set = isl_set_remove_empty_parts(set);
615 if (!set)
616 goto error;
617 isl_assert(set->ctx, set->n > 0, goto error);
618 c = isl_mat_alloc(set->ctx, 2, 2);
619 if (!c)
620 goto error;
621
622 if (set->p[0]->n_eq > 0) {
623 isl_assert(set->ctx, set->p[0]->n_eq == 1, goto error);
624 lower = c->row[0];
625 upper = c->row[1];
626 if (isl_int_is_pos(set->p[0]->eq[0][1])) {
627 isl_seq_cpy(lower, set->p[0]->eq[0], 2);
628 isl_seq_neg(upper, set->p[0]->eq[0], 2);
629 } else {
630 isl_seq_neg(lower, set->p[0]->eq[0], 2);
631 isl_seq_cpy(upper, set->p[0]->eq[0], 2);
632 }
633 } else {
634 for (j = 0; j < set->p[0]->n_ineq; ++j) {
635 if (isl_int_is_pos(set->p[0]->ineq[j][1])) {
636 lower = c->row[0];
637 isl_seq_cpy(lower, set->p[0]->ineq[j], 2);
638 } else {
639 upper = c->row[1];
640 isl_seq_cpy(upper, set->p[0]->ineq[j], 2);
641 }
642 }
643 }
644
645 isl_int_init(a);
646 isl_int_init(b);
647 for (i = 0; i < set->n; ++i) {
648 struct isl_basic_set *bset = set->p[i];
649 int has_lower = 0;
650 int has_upper = 0;
651
652 for (j = 0; j < bset->n_eq; ++j) {
653 has_lower = 1;
654 has_upper = 1;
655 if (lower) {
656 isl_int_mul(a, lower[0], bset->eq[j][1]);
657 isl_int_mul(b, lower[1], bset->eq[j][0]);
658 if (isl_int_lt(a, b) && isl_int_is_pos(bset->eq[j][1]))
659 isl_seq_cpy(lower, bset->eq[j], 2);
660 if (isl_int_gt(a, b) && isl_int_is_neg(bset->eq[j][1]))
661 isl_seq_neg(lower, bset->eq[j], 2);
662 }
663 if (upper) {
664 isl_int_mul(a, upper[0], bset->eq[j][1]);
665 isl_int_mul(b, upper[1], bset->eq[j][0]);
666 if (isl_int_lt(a, b) && isl_int_is_pos(bset->eq[j][1]))
667 isl_seq_neg(upper, bset->eq[j], 2);
668 if (isl_int_gt(a, b) && isl_int_is_neg(bset->eq[j][1]))
669 isl_seq_cpy(upper, bset->eq[j], 2);
670 }
671 }
672 for (j = 0; j < bset->n_ineq; ++j) {
673 if (isl_int_is_pos(bset->ineq[j][1]))
674 has_lower = 1;
675 if (isl_int_is_neg(bset->ineq[j][1]))
676 has_upper = 1;
677 if (lower && isl_int_is_pos(bset->ineq[j][1])) {
678 isl_int_mul(a, lower[0], bset->ineq[j][1]);
679 isl_int_mul(b, lower[1], bset->ineq[j][0]);
680 if (isl_int_lt(a, b))
681 isl_seq_cpy(lower, bset->ineq[j], 2);
682 }
683 if (upper && isl_int_is_neg(bset->ineq[j][1])) {
684 isl_int_mul(a, upper[0], bset->ineq[j][1]);
685 isl_int_mul(b, upper[1], bset->ineq[j][0]);
686 if (isl_int_gt(a, b))
687 isl_seq_cpy(upper, bset->ineq[j], 2);
688 }
689 }
690 if (!has_lower)
691 lower = NULL;
692 if (!has_upper)
693 upper = NULL;
694 }
695 isl_int_clear(a);
696 isl_int_clear(b);
697
698 hull = isl_basic_set_alloc(set->ctx, 0, 1, 0, 0, 2);
699 hull = isl_basic_set_set_rational(hull);
700 if (!hull)
701 goto error;
702 if (lower) {
703 k = isl_basic_set_alloc_inequality(hull);
704 isl_seq_cpy(hull->ineq[k], lower, 2);
705 }
706 if (upper) {
707 k = isl_basic_set_alloc_inequality(hull);
708 isl_seq_cpy(hull->ineq[k], upper, 2);
709 }
710 hull = isl_basic_set_finalize(hull);
711 isl_set_free(set);
712 isl_mat_free(c);
713 return hull;
714 error:
715 isl_set_free(set);
716 isl_mat_free(c);
717 return NULL;
718 }
719
convex_hull_0d(__isl_take isl_set * set)720 static __isl_give isl_basic_set *convex_hull_0d(__isl_take isl_set *set)
721 {
722 struct isl_basic_set *convex_hull;
723
724 if (!set)
725 return NULL;
726
727 if (isl_set_is_empty(set))
728 convex_hull = isl_basic_set_empty(isl_space_copy(set->dim));
729 else
730 convex_hull = isl_basic_set_universe(isl_space_copy(set->dim));
731 isl_set_free(set);
732 return convex_hull;
733 }
734
735 /* Compute the convex hull of a pair of basic sets without any parameters or
736 * integer divisions using Fourier-Motzkin elimination.
737 * The convex hull is the set of all points that can be written as
738 * the sum of points from both basic sets (in homogeneous coordinates).
739 * We set up the constraints in a space with dimensions for each of
740 * the three sets and then project out the dimensions corresponding
741 * to the two original basic sets, retaining only those corresponding
742 * to the convex hull.
743 */
convex_hull_pair_elim(__isl_take isl_basic_set * bset1,__isl_take isl_basic_set * bset2)744 static __isl_give isl_basic_set *convex_hull_pair_elim(
745 __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
746 {
747 int i, j, k;
748 struct isl_basic_set *bset[2];
749 struct isl_basic_set *hull = NULL;
750 isl_size dim;
751
752 dim = isl_basic_set_dim(bset1, isl_dim_set);
753 if (dim < 0 || !bset2)
754 goto error;
755
756 hull = isl_basic_set_alloc(bset1->ctx, 0, 2 + 3 * dim, 0,
757 1 + dim + bset1->n_eq + bset2->n_eq,
758 2 + bset1->n_ineq + bset2->n_ineq);
759 bset[0] = bset1;
760 bset[1] = bset2;
761 for (i = 0; i < 2; ++i) {
762 for (j = 0; j < bset[i]->n_eq; ++j) {
763 k = isl_basic_set_alloc_equality(hull);
764 if (k < 0)
765 goto error;
766 isl_seq_clr(hull->eq[k], (i+1) * (1+dim));
767 isl_seq_clr(hull->eq[k]+(i+2)*(1+dim), (1-i)*(1+dim));
768 isl_seq_cpy(hull->eq[k]+(i+1)*(1+dim), bset[i]->eq[j],
769 1+dim);
770 }
771 for (j = 0; j < bset[i]->n_ineq; ++j) {
772 k = isl_basic_set_alloc_inequality(hull);
773 if (k < 0)
774 goto error;
775 isl_seq_clr(hull->ineq[k], (i+1) * (1+dim));
776 isl_seq_clr(hull->ineq[k]+(i+2)*(1+dim), (1-i)*(1+dim));
777 isl_seq_cpy(hull->ineq[k]+(i+1)*(1+dim),
778 bset[i]->ineq[j], 1+dim);
779 }
780 k = isl_basic_set_alloc_inequality(hull);
781 if (k < 0)
782 goto error;
783 isl_seq_clr(hull->ineq[k], 1+2+3*dim);
784 isl_int_set_si(hull->ineq[k][(i+1)*(1+dim)], 1);
785 }
786 for (j = 0; j < 1+dim; ++j) {
787 k = isl_basic_set_alloc_equality(hull);
788 if (k < 0)
789 goto error;
790 isl_seq_clr(hull->eq[k], 1+2+3*dim);
791 isl_int_set_si(hull->eq[k][j], -1);
792 isl_int_set_si(hull->eq[k][1+dim+j], 1);
793 isl_int_set_si(hull->eq[k][2*(1+dim)+j], 1);
794 }
795 hull = isl_basic_set_set_rational(hull);
796 hull = isl_basic_set_remove_dims(hull, isl_dim_set, dim, 2*(1+dim));
797 hull = isl_basic_set_remove_redundancies(hull);
798 isl_basic_set_free(bset1);
799 isl_basic_set_free(bset2);
800 return hull;
801 error:
802 isl_basic_set_free(bset1);
803 isl_basic_set_free(bset2);
804 isl_basic_set_free(hull);
805 return NULL;
806 }
807
808 /* Is the set bounded for each value of the parameters?
809 */
isl_basic_set_is_bounded(__isl_keep isl_basic_set * bset)810 isl_bool isl_basic_set_is_bounded(__isl_keep isl_basic_set *bset)
811 {
812 struct isl_tab *tab;
813 isl_bool bounded;
814
815 if (!bset)
816 return isl_bool_error;
817 if (isl_basic_set_plain_is_empty(bset))
818 return isl_bool_true;
819
820 tab = isl_tab_from_recession_cone(bset, 1);
821 bounded = isl_tab_cone_is_bounded(tab);
822 isl_tab_free(tab);
823 return bounded;
824 }
825
826 /* Is the image bounded for each value of the parameters and
827 * the domain variables?
828 */
isl_basic_map_image_is_bounded(__isl_keep isl_basic_map * bmap)829 isl_bool isl_basic_map_image_is_bounded(__isl_keep isl_basic_map *bmap)
830 {
831 isl_size nparam = isl_basic_map_dim(bmap, isl_dim_param);
832 isl_size n_in = isl_basic_map_dim(bmap, isl_dim_in);
833 isl_bool bounded;
834
835 if (nparam < 0 || n_in < 0)
836 return isl_bool_error;
837
838 bmap = isl_basic_map_copy(bmap);
839 bmap = isl_basic_map_cow(bmap);
840 bmap = isl_basic_map_move_dims(bmap, isl_dim_param, nparam,
841 isl_dim_in, 0, n_in);
842 bounded = isl_basic_set_is_bounded(bset_from_bmap(bmap));
843 isl_basic_map_free(bmap);
844
845 return bounded;
846 }
847
848 /* Is the set bounded for each value of the parameters?
849 */
isl_set_is_bounded(__isl_keep isl_set * set)850 isl_bool isl_set_is_bounded(__isl_keep isl_set *set)
851 {
852 int i;
853
854 if (!set)
855 return isl_bool_error;
856
857 for (i = 0; i < set->n; ++i) {
858 isl_bool bounded = isl_basic_set_is_bounded(set->p[i]);
859 if (!bounded || bounded < 0)
860 return bounded;
861 }
862 return isl_bool_true;
863 }
864
865 /* Compute the lineality space of the convex hull of bset1 and bset2.
866 *
867 * We first compute the intersection of the recession cone of bset1
868 * with the negative of the recession cone of bset2 and then compute
869 * the linear hull of the resulting cone.
870 */
induced_lineality_space(__isl_take isl_basic_set * bset1,__isl_take isl_basic_set * bset2)871 static __isl_give isl_basic_set *induced_lineality_space(
872 __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
873 {
874 int i, k;
875 struct isl_basic_set *lin = NULL;
876 isl_size dim;
877
878 dim = isl_basic_set_dim(bset1, isl_dim_all);
879 if (dim < 0 || !bset2)
880 goto error;
881
882 lin = isl_basic_set_alloc_space(isl_basic_set_get_space(bset1), 0,
883 bset1->n_eq + bset2->n_eq,
884 bset1->n_ineq + bset2->n_ineq);
885 lin = isl_basic_set_set_rational(lin);
886 if (!lin)
887 goto error;
888 for (i = 0; i < bset1->n_eq; ++i) {
889 k = isl_basic_set_alloc_equality(lin);
890 if (k < 0)
891 goto error;
892 isl_int_set_si(lin->eq[k][0], 0);
893 isl_seq_cpy(lin->eq[k] + 1, bset1->eq[i] + 1, dim);
894 }
895 for (i = 0; i < bset1->n_ineq; ++i) {
896 k = isl_basic_set_alloc_inequality(lin);
897 if (k < 0)
898 goto error;
899 isl_int_set_si(lin->ineq[k][0], 0);
900 isl_seq_cpy(lin->ineq[k] + 1, bset1->ineq[i] + 1, dim);
901 }
902 for (i = 0; i < bset2->n_eq; ++i) {
903 k = isl_basic_set_alloc_equality(lin);
904 if (k < 0)
905 goto error;
906 isl_int_set_si(lin->eq[k][0], 0);
907 isl_seq_neg(lin->eq[k] + 1, bset2->eq[i] + 1, dim);
908 }
909 for (i = 0; i < bset2->n_ineq; ++i) {
910 k = isl_basic_set_alloc_inequality(lin);
911 if (k < 0)
912 goto error;
913 isl_int_set_si(lin->ineq[k][0], 0);
914 isl_seq_neg(lin->ineq[k] + 1, bset2->ineq[i] + 1, dim);
915 }
916
917 isl_basic_set_free(bset1);
918 isl_basic_set_free(bset2);
919 return isl_basic_set_affine_hull(lin);
920 error:
921 isl_basic_set_free(lin);
922 isl_basic_set_free(bset1);
923 isl_basic_set_free(bset2);
924 return NULL;
925 }
926
927 static __isl_give isl_basic_set *uset_convex_hull(__isl_take isl_set *set);
928
929 /* Given a set and a linear space "lin" of dimension n > 0,
930 * project the linear space from the set, compute the convex hull
931 * and then map the set back to the original space.
932 *
933 * Let
934 *
935 * M x = 0
936 *
937 * describe the linear space. We first compute the Hermite normal
938 * form H = M U of M = H Q, to obtain
939 *
940 * H Q x = 0
941 *
942 * The last n rows of H will be zero, so the last n variables of x' = Q x
943 * are the one we want to project out. We do this by transforming each
944 * basic set A x >= b to A U x' >= b and then removing the last n dimensions.
945 * After computing the convex hull in x'_1, i.e., A' x'_1 >= b',
946 * we transform the hull back to the original space as A' Q_1 x >= b',
947 * with Q_1 all but the last n rows of Q.
948 */
modulo_lineality(__isl_take isl_set * set,__isl_take isl_basic_set * lin)949 static __isl_give isl_basic_set *modulo_lineality(__isl_take isl_set *set,
950 __isl_take isl_basic_set *lin)
951 {
952 isl_size total = isl_basic_set_dim(lin, isl_dim_all);
953 unsigned lin_dim;
954 struct isl_basic_set *hull;
955 struct isl_mat *M, *U, *Q;
956
957 if (!set || total < 0)
958 goto error;
959 lin_dim = total - lin->n_eq;
960 M = isl_mat_sub_alloc6(set->ctx, lin->eq, 0, lin->n_eq, 1, total);
961 M = isl_mat_left_hermite(M, 0, &U, &Q);
962 if (!M)
963 goto error;
964 isl_mat_free(M);
965 isl_basic_set_free(lin);
966
967 Q = isl_mat_drop_rows(Q, Q->n_row - lin_dim, lin_dim);
968
969 U = isl_mat_lin_to_aff(U);
970 Q = isl_mat_lin_to_aff(Q);
971
972 set = isl_set_preimage(set, U);
973 set = isl_set_remove_dims(set, isl_dim_set, total - lin_dim, lin_dim);
974 hull = uset_convex_hull(set);
975 hull = isl_basic_set_preimage(hull, Q);
976
977 return hull;
978 error:
979 isl_basic_set_free(lin);
980 isl_set_free(set);
981 return NULL;
982 }
983
984 /* Given two polyhedra with as constraints h_{ij} x >= 0 in homegeneous space,
985 * set up an LP for solving
986 *
987 * \sum_j \alpha_{1j} h_{1j} = \sum_j \alpha_{2j} h_{2j}
988 *
989 * \alpha{i0} corresponds to the (implicit) positivity constraint 1 >= 0
990 * The next \alpha{ij} correspond to the equalities and come in pairs.
991 * The final \alpha{ij} correspond to the inequalities.
992 */
valid_direction_lp(__isl_take isl_basic_set * bset1,__isl_take isl_basic_set * bset2)993 static __isl_give isl_basic_set *valid_direction_lp(
994 __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
995 {
996 isl_space *space;
997 struct isl_basic_set *lp;
998 unsigned d;
999 int n;
1000 int i, j, k;
1001 isl_size total;
1002
1003 total = isl_basic_set_dim(bset1, isl_dim_all);
1004 if (total < 0 || !bset2)
1005 goto error;
1006 d = 1 + total;
1007 n = 2 +
1008 2 * bset1->n_eq + bset1->n_ineq + 2 * bset2->n_eq + bset2->n_ineq;
1009 space = isl_space_set_alloc(bset1->ctx, 0, n);
1010 lp = isl_basic_set_alloc_space(space, 0, d, n);
1011 if (!lp)
1012 goto error;
1013 for (i = 0; i < n; ++i) {
1014 k = isl_basic_set_alloc_inequality(lp);
1015 if (k < 0)
1016 goto error;
1017 isl_seq_clr(lp->ineq[k] + 1, n);
1018 isl_int_set_si(lp->ineq[k][0], -1);
1019 isl_int_set_si(lp->ineq[k][1 + i], 1);
1020 }
1021 for (i = 0; i < d; ++i) {
1022 k = isl_basic_set_alloc_equality(lp);
1023 if (k < 0)
1024 goto error;
1025 n = 0;
1026 isl_int_set_si(lp->eq[k][n], 0); n++;
1027 /* positivity constraint 1 >= 0 */
1028 isl_int_set_si(lp->eq[k][n], i == 0); n++;
1029 for (j = 0; j < bset1->n_eq; ++j) {
1030 isl_int_set(lp->eq[k][n], bset1->eq[j][i]); n++;
1031 isl_int_neg(lp->eq[k][n], bset1->eq[j][i]); n++;
1032 }
1033 for (j = 0; j < bset1->n_ineq; ++j) {
1034 isl_int_set(lp->eq[k][n], bset1->ineq[j][i]); n++;
1035 }
1036 /* positivity constraint 1 >= 0 */
1037 isl_int_set_si(lp->eq[k][n], -(i == 0)); n++;
1038 for (j = 0; j < bset2->n_eq; ++j) {
1039 isl_int_neg(lp->eq[k][n], bset2->eq[j][i]); n++;
1040 isl_int_set(lp->eq[k][n], bset2->eq[j][i]); n++;
1041 }
1042 for (j = 0; j < bset2->n_ineq; ++j) {
1043 isl_int_neg(lp->eq[k][n], bset2->ineq[j][i]); n++;
1044 }
1045 }
1046 lp = isl_basic_set_gauss(lp, NULL);
1047 isl_basic_set_free(bset1);
1048 isl_basic_set_free(bset2);
1049 return lp;
1050 error:
1051 isl_basic_set_free(bset1);
1052 isl_basic_set_free(bset2);
1053 return NULL;
1054 }
1055
1056 /* Compute a vector s in the homogeneous space such that <s, r> > 0
1057 * for all rays in the homogeneous space of the two cones that correspond
1058 * to the input polyhedra bset1 and bset2.
1059 *
1060 * We compute s as a vector that satisfies
1061 *
1062 * s = \sum_j \alpha_{ij} h_{ij} for i = 1,2 (*)
1063 *
1064 * with h_{ij} the normals of the facets of polyhedron i
1065 * (including the "positivity constraint" 1 >= 0) and \alpha_{ij}
1066 * strictly positive numbers. For simplicity we impose \alpha_{ij} >= 1.
1067 * We first set up an LP with as variables the \alpha{ij}.
1068 * In this formulation, for each polyhedron i,
1069 * the first constraint is the positivity constraint, followed by pairs
1070 * of variables for the equalities, followed by variables for the inequalities.
1071 * We then simply pick a feasible solution and compute s using (*).
1072 *
1073 * Note that we simply pick any valid direction and make no attempt
1074 * to pick a "good" or even the "best" valid direction.
1075 */
valid_direction(__isl_take isl_basic_set * bset1,__isl_take isl_basic_set * bset2)1076 static __isl_give isl_vec *valid_direction(
1077 __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
1078 {
1079 struct isl_basic_set *lp;
1080 struct isl_tab *tab;
1081 struct isl_vec *sample = NULL;
1082 struct isl_vec *dir;
1083 isl_size d;
1084 int i;
1085 int n;
1086
1087 if (!bset1 || !bset2)
1088 goto error;
1089 lp = valid_direction_lp(isl_basic_set_copy(bset1),
1090 isl_basic_set_copy(bset2));
1091 tab = isl_tab_from_basic_set(lp, 0);
1092 sample = isl_tab_get_sample_value(tab);
1093 isl_tab_free(tab);
1094 isl_basic_set_free(lp);
1095 if (!sample)
1096 goto error;
1097 d = isl_basic_set_dim(bset1, isl_dim_all);
1098 if (d < 0)
1099 goto error;
1100 dir = isl_vec_alloc(bset1->ctx, 1 + d);
1101 if (!dir)
1102 goto error;
1103 isl_seq_clr(dir->block.data + 1, dir->size - 1);
1104 n = 1;
1105 /* positivity constraint 1 >= 0 */
1106 isl_int_set(dir->block.data[0], sample->block.data[n]); n++;
1107 for (i = 0; i < bset1->n_eq; ++i) {
1108 isl_int_sub(sample->block.data[n],
1109 sample->block.data[n], sample->block.data[n+1]);
1110 isl_seq_combine(dir->block.data,
1111 bset1->ctx->one, dir->block.data,
1112 sample->block.data[n], bset1->eq[i], 1 + d);
1113
1114 n += 2;
1115 }
1116 for (i = 0; i < bset1->n_ineq; ++i)
1117 isl_seq_combine(dir->block.data,
1118 bset1->ctx->one, dir->block.data,
1119 sample->block.data[n++], bset1->ineq[i], 1 + d);
1120 isl_vec_free(sample);
1121 isl_seq_normalize(bset1->ctx, dir->el, dir->size);
1122 isl_basic_set_free(bset1);
1123 isl_basic_set_free(bset2);
1124 return dir;
1125 error:
1126 isl_vec_free(sample);
1127 isl_basic_set_free(bset1);
1128 isl_basic_set_free(bset2);
1129 return NULL;
1130 }
1131
1132 /* Given a polyhedron b_i + A_i x >= 0 and a map T = S^{-1},
1133 * compute b_i' + A_i' x' >= 0, with
1134 *
1135 * [ b_i A_i ] [ y' ] [ y' ]
1136 * [ 1 0 ] S^{-1} [ x' ] >= 0 or [ b_i' A_i' ] [ x' ] >= 0
1137 *
1138 * In particular, add the "positivity constraint" and then perform
1139 * the mapping.
1140 */
homogeneous_map(__isl_take isl_basic_set * bset,__isl_take isl_mat * T)1141 static __isl_give isl_basic_set *homogeneous_map(__isl_take isl_basic_set *bset,
1142 __isl_take isl_mat *T)
1143 {
1144 int k;
1145 isl_size total;
1146
1147 total = isl_basic_set_dim(bset, isl_dim_all);
1148 if (total < 0)
1149 goto error;
1150 bset = isl_basic_set_extend_constraints(bset, 0, 1);
1151 k = isl_basic_set_alloc_inequality(bset);
1152 if (k < 0)
1153 goto error;
1154 isl_seq_clr(bset->ineq[k] + 1, total);
1155 isl_int_set_si(bset->ineq[k][0], 1);
1156 bset = isl_basic_set_preimage(bset, T);
1157 return bset;
1158 error:
1159 isl_mat_free(T);
1160 isl_basic_set_free(bset);
1161 return NULL;
1162 }
1163
1164 /* Compute the convex hull of a pair of basic sets without any parameters or
1165 * integer divisions, where the convex hull is known to be pointed,
1166 * but the basic sets may be unbounded.
1167 *
1168 * We turn this problem into the computation of a convex hull of a pair
1169 * _bounded_ polyhedra by "changing the direction of the homogeneous
1170 * dimension". This idea is due to Matthias Koeppe.
1171 *
1172 * Consider the cones in homogeneous space that correspond to the
1173 * input polyhedra. The rays of these cones are also rays of the
1174 * polyhedra if the coordinate that corresponds to the homogeneous
1175 * dimension is zero. That is, if the inner product of the rays
1176 * with the homogeneous direction is zero.
1177 * The cones in the homogeneous space can also be considered to
1178 * correspond to other pairs of polyhedra by chosing a different
1179 * homogeneous direction. To ensure that both of these polyhedra
1180 * are bounded, we need to make sure that all rays of the cones
1181 * correspond to vertices and not to rays.
1182 * Let s be a direction such that <s, r> > 0 for all rays r of both cones.
1183 * Then using s as a homogeneous direction, we obtain a pair of polytopes.
1184 * The vector s is computed in valid_direction.
1185 *
1186 * Note that we need to consider _all_ rays of the cones and not just
1187 * the rays that correspond to rays in the polyhedra. If we were to
1188 * only consider those rays and turn them into vertices, then we
1189 * may inadvertently turn some vertices into rays.
1190 *
1191 * The standard homogeneous direction is the unit vector in the 0th coordinate.
1192 * We therefore transform the two polyhedra such that the selected
1193 * direction is mapped onto this standard direction and then proceed
1194 * with the normal computation.
1195 * Let S be a non-singular square matrix with s as its first row,
1196 * then we want to map the polyhedra to the space
1197 *
1198 * [ y' ] [ y ] [ y ] [ y' ]
1199 * [ x' ] = S [ x ] i.e., [ x ] = S^{-1} [ x' ]
1200 *
1201 * We take S to be the unimodular completion of s to limit the growth
1202 * of the coefficients in the following computations.
1203 *
1204 * Let b_i + A_i x >= 0 be the constraints of polyhedron i.
1205 * We first move to the homogeneous dimension
1206 *
1207 * b_i y + A_i x >= 0 [ b_i A_i ] [ y ] [ 0 ]
1208 * y >= 0 or [ 1 0 ] [ x ] >= [ 0 ]
1209 *
1210 * Then we change directoin
1211 *
1212 * [ b_i A_i ] [ y' ] [ y' ]
1213 * [ 1 0 ] S^{-1} [ x' ] >= 0 or [ b_i' A_i' ] [ x' ] >= 0
1214 *
1215 * Then we compute the convex hull of the polytopes b_i' + A_i' x' >= 0
1216 * resulting in b' + A' x' >= 0, which we then convert back
1217 *
1218 * [ y ] [ y ]
1219 * [ b' A' ] S [ x ] >= 0 or [ b A ] [ x ] >= 0
1220 *
1221 * The polyhedron b + A x >= 0 is then the convex hull of the input polyhedra.
1222 */
convex_hull_pair_pointed(__isl_take isl_basic_set * bset1,__isl_take isl_basic_set * bset2)1223 static __isl_give isl_basic_set *convex_hull_pair_pointed(
1224 __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
1225 {
1226 struct isl_ctx *ctx = NULL;
1227 struct isl_vec *dir = NULL;
1228 struct isl_mat *T = NULL;
1229 struct isl_mat *T2 = NULL;
1230 struct isl_basic_set *hull;
1231 struct isl_set *set;
1232
1233 if (!bset1 || !bset2)
1234 goto error;
1235 ctx = isl_basic_set_get_ctx(bset1);
1236 dir = valid_direction(isl_basic_set_copy(bset1),
1237 isl_basic_set_copy(bset2));
1238 if (!dir)
1239 goto error;
1240 T = isl_mat_alloc(ctx, dir->size, dir->size);
1241 if (!T)
1242 goto error;
1243 isl_seq_cpy(T->row[0], dir->block.data, dir->size);
1244 T = isl_mat_unimodular_complete(T, 1);
1245 T2 = isl_mat_right_inverse(isl_mat_copy(T));
1246
1247 bset1 = homogeneous_map(bset1, isl_mat_copy(T2));
1248 bset2 = homogeneous_map(bset2, T2);
1249 set = isl_set_alloc_space(isl_basic_set_get_space(bset1), 2, 0);
1250 set = isl_set_add_basic_set(set, bset1);
1251 set = isl_set_add_basic_set(set, bset2);
1252 hull = uset_convex_hull(set);
1253 hull = isl_basic_set_preimage(hull, T);
1254
1255 isl_vec_free(dir);
1256
1257 return hull;
1258 error:
1259 isl_vec_free(dir);
1260 isl_basic_set_free(bset1);
1261 isl_basic_set_free(bset2);
1262 return NULL;
1263 }
1264
1265 static __isl_give isl_basic_set *uset_convex_hull_wrap(__isl_take isl_set *set);
1266 static __isl_give isl_basic_set *modulo_affine_hull(
1267 __isl_take isl_set *set, __isl_take isl_basic_set *affine_hull);
1268
1269 /* Compute the convex hull of a pair of basic sets without any parameters or
1270 * integer divisions.
1271 *
1272 * This function is called from uset_convex_hull_unbounded, which
1273 * means that the complete convex hull is unbounded. Some pairs
1274 * of basic sets may still be bounded, though.
1275 * They may even lie inside a lower dimensional space, in which
1276 * case they need to be handled inside their affine hull since
1277 * the main algorithm assumes that the result is full-dimensional.
1278 *
1279 * If the convex hull of the two basic sets would have a non-trivial
1280 * lineality space, we first project out this lineality space.
1281 */
convex_hull_pair(__isl_take isl_basic_set * bset1,__isl_take isl_basic_set * bset2)1282 static __isl_give isl_basic_set *convex_hull_pair(
1283 __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
1284 {
1285 isl_basic_set *lin, *aff;
1286 isl_bool bounded1, bounded2;
1287 isl_size total;
1288
1289 if (bset1->ctx->opt->convex == ISL_CONVEX_HULL_FM)
1290 return convex_hull_pair_elim(bset1, bset2);
1291
1292 aff = isl_set_affine_hull(isl_basic_set_union(isl_basic_set_copy(bset1),
1293 isl_basic_set_copy(bset2)));
1294 if (!aff)
1295 goto error;
1296 if (aff->n_eq != 0)
1297 return modulo_affine_hull(isl_basic_set_union(bset1, bset2), aff);
1298 isl_basic_set_free(aff);
1299
1300 bounded1 = isl_basic_set_is_bounded(bset1);
1301 bounded2 = isl_basic_set_is_bounded(bset2);
1302
1303 if (bounded1 < 0 || bounded2 < 0)
1304 goto error;
1305
1306 if (bounded1 && bounded2)
1307 return uset_convex_hull_wrap(isl_basic_set_union(bset1, bset2));
1308
1309 if (bounded1 || bounded2)
1310 return convex_hull_pair_pointed(bset1, bset2);
1311
1312 lin = induced_lineality_space(isl_basic_set_copy(bset1),
1313 isl_basic_set_copy(bset2));
1314 if (!lin)
1315 goto error;
1316 if (isl_basic_set_plain_is_universe(lin)) {
1317 isl_basic_set_free(bset1);
1318 isl_basic_set_free(bset2);
1319 return lin;
1320 }
1321 total = isl_basic_set_dim(lin, isl_dim_all);
1322 if (lin->n_eq < total) {
1323 struct isl_set *set;
1324 set = isl_set_alloc_space(isl_basic_set_get_space(bset1), 2, 0);
1325 set = isl_set_add_basic_set(set, bset1);
1326 set = isl_set_add_basic_set(set, bset2);
1327 return modulo_lineality(set, lin);
1328 }
1329 isl_basic_set_free(lin);
1330 if (total < 0)
1331 goto error;
1332
1333 return convex_hull_pair_pointed(bset1, bset2);
1334 error:
1335 isl_basic_set_free(bset1);
1336 isl_basic_set_free(bset2);
1337 return NULL;
1338 }
1339
1340 /* Compute the lineality space of a basic set.
1341 * We basically just drop the constants and turn every inequality
1342 * into an equality.
1343 * Any explicit representations of local variables are removed
1344 * because they may no longer be valid representations
1345 * in the lineality space.
1346 */
isl_basic_set_lineality_space(__isl_take isl_basic_set * bset)1347 __isl_give isl_basic_set *isl_basic_set_lineality_space(
1348 __isl_take isl_basic_set *bset)
1349 {
1350 int i, k;
1351 struct isl_basic_set *lin = NULL;
1352 isl_size n_div, dim;
1353
1354 n_div = isl_basic_set_dim(bset, isl_dim_div);
1355 dim = isl_basic_set_dim(bset, isl_dim_all);
1356 if (n_div < 0 || dim < 0)
1357 return isl_basic_set_free(bset);
1358
1359 lin = isl_basic_set_alloc_space(isl_basic_set_get_space(bset),
1360 n_div, dim, 0);
1361 for (i = 0; i < n_div; ++i)
1362 if (isl_basic_set_alloc_div(lin) < 0)
1363 goto error;
1364 if (!lin)
1365 goto error;
1366 for (i = 0; i < bset->n_eq; ++i) {
1367 k = isl_basic_set_alloc_equality(lin);
1368 if (k < 0)
1369 goto error;
1370 isl_int_set_si(lin->eq[k][0], 0);
1371 isl_seq_cpy(lin->eq[k] + 1, bset->eq[i] + 1, dim);
1372 }
1373 lin = isl_basic_set_gauss(lin, NULL);
1374 if (!lin)
1375 goto error;
1376 for (i = 0; i < bset->n_ineq && lin->n_eq < dim; ++i) {
1377 k = isl_basic_set_alloc_equality(lin);
1378 if (k < 0)
1379 goto error;
1380 isl_int_set_si(lin->eq[k][0], 0);
1381 isl_seq_cpy(lin->eq[k] + 1, bset->ineq[i] + 1, dim);
1382 lin = isl_basic_set_gauss(lin, NULL);
1383 if (!lin)
1384 goto error;
1385 }
1386 isl_basic_set_free(bset);
1387 return lin;
1388 error:
1389 isl_basic_set_free(lin);
1390 isl_basic_set_free(bset);
1391 return NULL;
1392 }
1393
1394 /* Compute the (linear) hull of the lineality spaces of the basic sets in the
1395 * set "set".
1396 */
isl_set_combined_lineality_space(__isl_take isl_set * set)1397 __isl_give isl_basic_set *isl_set_combined_lineality_space(
1398 __isl_take isl_set *set)
1399 {
1400 int i;
1401 struct isl_set *lin = NULL;
1402
1403 if (!set)
1404 return NULL;
1405 if (set->n == 0) {
1406 isl_space *space = isl_set_get_space(set);
1407 isl_set_free(set);
1408 return isl_basic_set_empty(space);
1409 }
1410
1411 lin = isl_set_alloc_space(isl_set_get_space(set), set->n, 0);
1412 for (i = 0; i < set->n; ++i)
1413 lin = isl_set_add_basic_set(lin,
1414 isl_basic_set_lineality_space(isl_basic_set_copy(set->p[i])));
1415 isl_set_free(set);
1416 return isl_set_affine_hull(lin);
1417 }
1418
1419 /* Compute the convex hull of a set without any parameters or
1420 * integer divisions.
1421 * In each step, we combined two basic sets until only one
1422 * basic set is left.
1423 * The input basic sets are assumed not to have a non-trivial
1424 * lineality space. If any of the intermediate results has
1425 * a non-trivial lineality space, it is projected out.
1426 */
uset_convex_hull_unbounded(__isl_take isl_set * set)1427 static __isl_give isl_basic_set *uset_convex_hull_unbounded(
1428 __isl_take isl_set *set)
1429 {
1430 isl_basic_set_list *list;
1431
1432 list = isl_set_get_basic_set_list(set);
1433 isl_set_free(set);
1434
1435 while (list) {
1436 isl_size n, total;
1437 struct isl_basic_set *t;
1438 isl_basic_set *bset1, *bset2;
1439
1440 n = isl_basic_set_list_n_basic_set(list);
1441 if (n < 0)
1442 goto error;
1443 if (n < 2)
1444 isl_die(isl_basic_set_list_get_ctx(list),
1445 isl_error_internal,
1446 "expecting at least two elements", goto error);
1447 bset1 = isl_basic_set_list_get_basic_set(list, n - 1);
1448 bset2 = isl_basic_set_list_get_basic_set(list, n - 2);
1449 bset1 = convex_hull_pair(bset1, bset2);
1450 if (n == 2) {
1451 isl_basic_set_list_free(list);
1452 return bset1;
1453 }
1454 bset1 = isl_basic_set_underlying_set(bset1);
1455 list = isl_basic_set_list_drop(list, n - 2, 2);
1456 list = isl_basic_set_list_add(list, bset1);
1457
1458 t = isl_basic_set_list_get_basic_set(list, n - 2);
1459 t = isl_basic_set_lineality_space(t);
1460 if (!t)
1461 goto error;
1462 if (isl_basic_set_plain_is_universe(t)) {
1463 isl_basic_set_list_free(list);
1464 return t;
1465 }
1466 total = isl_basic_set_dim(t, isl_dim_all);
1467 if (t->n_eq < total) {
1468 set = isl_basic_set_list_union(list);
1469 return modulo_lineality(set, t);
1470 }
1471 isl_basic_set_free(t);
1472 if (total < 0)
1473 goto error;
1474 }
1475
1476 return NULL;
1477 error:
1478 isl_basic_set_list_free(list);
1479 return NULL;
1480 }
1481
1482 /* Compute an initial hull for wrapping containing a single initial
1483 * facet.
1484 * This function assumes that the given set is bounded.
1485 */
initial_hull(__isl_take isl_basic_set * hull,__isl_keep isl_set * set)1486 static __isl_give isl_basic_set *initial_hull(__isl_take isl_basic_set *hull,
1487 __isl_keep isl_set *set)
1488 {
1489 struct isl_mat *bounds = NULL;
1490 isl_size dim;
1491 int k;
1492
1493 if (!hull)
1494 goto error;
1495 bounds = initial_facet_constraint(set);
1496 if (!bounds)
1497 goto error;
1498 k = isl_basic_set_alloc_inequality(hull);
1499 if (k < 0)
1500 goto error;
1501 dim = isl_set_dim(set, isl_dim_set);
1502 if (dim < 0)
1503 goto error;
1504 isl_assert(set->ctx, 1 + dim == bounds->n_col, goto error);
1505 isl_seq_cpy(hull->ineq[k], bounds->row[0], bounds->n_col);
1506 isl_mat_free(bounds);
1507
1508 return hull;
1509 error:
1510 isl_basic_set_free(hull);
1511 isl_mat_free(bounds);
1512 return NULL;
1513 }
1514
1515 struct max_constraint {
1516 struct isl_mat *c;
1517 int count;
1518 int ineq;
1519 };
1520
max_constraint_equal(const void * entry,const void * val)1521 static isl_bool max_constraint_equal(const void *entry, const void *val)
1522 {
1523 struct max_constraint *a = (struct max_constraint *)entry;
1524 isl_int *b = (isl_int *)val;
1525
1526 return isl_bool_ok(isl_seq_eq(a->c->row[0] + 1, b, a->c->n_col - 1));
1527 }
1528
update_constraint(struct isl_ctx * ctx,struct isl_hash_table * table,isl_int * con,unsigned len,int n,int ineq)1529 static isl_stat update_constraint(struct isl_ctx *ctx,
1530 struct isl_hash_table *table,
1531 isl_int *con, unsigned len, int n, int ineq)
1532 {
1533 struct isl_hash_table_entry *entry;
1534 struct max_constraint *c;
1535 uint32_t c_hash;
1536
1537 c_hash = isl_seq_get_hash(con + 1, len);
1538 entry = isl_hash_table_find(ctx, table, c_hash, max_constraint_equal,
1539 con + 1, 0);
1540 if (!entry)
1541 return isl_stat_error;
1542 if (entry == isl_hash_table_entry_none)
1543 return isl_stat_ok;
1544 c = entry->data;
1545 if (c->count < n) {
1546 isl_hash_table_remove(ctx, table, entry);
1547 return isl_stat_ok;
1548 }
1549 c->count++;
1550 if (isl_int_gt(c->c->row[0][0], con[0]))
1551 return isl_stat_ok;
1552 if (isl_int_eq(c->c->row[0][0], con[0])) {
1553 if (ineq)
1554 c->ineq = ineq;
1555 return isl_stat_ok;
1556 }
1557 c->c = isl_mat_cow(c->c);
1558 isl_int_set(c->c->row[0][0], con[0]);
1559 c->ineq = ineq;
1560
1561 return isl_stat_ok;
1562 }
1563
1564 /* Check whether the constraint hash table "table" contains the constraint
1565 * "con".
1566 */
has_constraint(struct isl_ctx * ctx,struct isl_hash_table * table,isl_int * con,unsigned len,int n)1567 static isl_bool has_constraint(struct isl_ctx *ctx,
1568 struct isl_hash_table *table, isl_int *con, unsigned len, int n)
1569 {
1570 struct isl_hash_table_entry *entry;
1571 struct max_constraint *c;
1572 uint32_t c_hash;
1573
1574 c_hash = isl_seq_get_hash(con + 1, len);
1575 entry = isl_hash_table_find(ctx, table, c_hash, max_constraint_equal,
1576 con + 1, 0);
1577 if (!entry)
1578 return isl_bool_error;
1579 if (entry == isl_hash_table_entry_none)
1580 return isl_bool_false;
1581 c = entry->data;
1582 if (c->count < n)
1583 return isl_bool_false;
1584 return isl_bool_ok(isl_int_eq(c->c->row[0][0], con[0]));
1585 }
1586
1587 /* Are the constraints of "bset" known to be facets?
1588 * If there are any equality constraints, then they are not.
1589 * If there may be redundant constraints, then those
1590 * redundant constraints are not facets.
1591 */
has_facets(__isl_keep isl_basic_set * bset)1592 static isl_bool has_facets(__isl_keep isl_basic_set *bset)
1593 {
1594 isl_size n_eq;
1595
1596 n_eq = isl_basic_set_n_equality(bset);
1597 if (n_eq < 0)
1598 return isl_bool_error;
1599 if (n_eq != 0)
1600 return isl_bool_false;
1601 return ISL_F_ISSET(bset, ISL_BASIC_SET_NO_REDUNDANT);
1602 }
1603
1604 /* Check for inequality constraints of a basic set without equalities
1605 * or redundant constraints
1606 * such that the same or more stringent copies of the constraint appear
1607 * in all of the basic sets. Such constraints are necessarily facet
1608 * constraints of the convex hull.
1609 *
1610 * If the resulting basic set is by chance identical to one of
1611 * the basic sets in "set", then we know that this basic set contains
1612 * all other basic sets and is therefore the convex hull of set.
1613 * In this case we set *is_hull to 1.
1614 */
common_constraints(__isl_take isl_basic_set * hull,__isl_keep isl_set * set,int * is_hull)1615 static __isl_give isl_basic_set *common_constraints(
1616 __isl_take isl_basic_set *hull, __isl_keep isl_set *set, int *is_hull)
1617 {
1618 int i, j, s, n;
1619 int min_constraints;
1620 int best;
1621 struct max_constraint *constraints = NULL;
1622 struct isl_hash_table *table = NULL;
1623 isl_size total;
1624
1625 *is_hull = 0;
1626
1627 for (i = 0; i < set->n; ++i) {
1628 isl_bool facets = has_facets(set->p[i]);
1629 if (facets < 0)
1630 return isl_basic_set_free(hull);
1631 if (facets)
1632 break;
1633 }
1634 if (i >= set->n)
1635 return hull;
1636 min_constraints = set->p[i]->n_ineq;
1637 best = i;
1638 for (i = best + 1; i < set->n; ++i) {
1639 isl_bool facets = has_facets(set->p[i]);
1640 if (facets < 0)
1641 return isl_basic_set_free(hull);
1642 if (!facets)
1643 continue;
1644 if (set->p[i]->n_ineq >= min_constraints)
1645 continue;
1646 min_constraints = set->p[i]->n_ineq;
1647 best = i;
1648 }
1649 constraints = isl_calloc_array(hull->ctx, struct max_constraint,
1650 min_constraints);
1651 if (!constraints)
1652 return hull;
1653 table = isl_alloc_type(hull->ctx, struct isl_hash_table);
1654 if (isl_hash_table_init(hull->ctx, table, min_constraints))
1655 goto error;
1656
1657 total = isl_set_dim(set, isl_dim_all);
1658 if (total < 0)
1659 goto error;
1660 for (i = 0; i < set->p[best]->n_ineq; ++i) {
1661 constraints[i].c = isl_mat_sub_alloc6(hull->ctx,
1662 set->p[best]->ineq + i, 0, 1, 0, 1 + total);
1663 if (!constraints[i].c)
1664 goto error;
1665 constraints[i].ineq = 1;
1666 }
1667 for (i = 0; i < min_constraints; ++i) {
1668 struct isl_hash_table_entry *entry;
1669 uint32_t c_hash;
1670 c_hash = isl_seq_get_hash(constraints[i].c->row[0] + 1, total);
1671 entry = isl_hash_table_find(hull->ctx, table, c_hash,
1672 max_constraint_equal, constraints[i].c->row[0] + 1, 1);
1673 if (!entry)
1674 goto error;
1675 isl_assert(hull->ctx, !entry->data, goto error);
1676 entry->data = &constraints[i];
1677 }
1678
1679 n = 0;
1680 for (s = 0; s < set->n; ++s) {
1681 if (s == best)
1682 continue;
1683
1684 for (i = 0; i < set->p[s]->n_eq; ++i) {
1685 isl_int *eq = set->p[s]->eq[i];
1686 for (j = 0; j < 2; ++j) {
1687 isl_seq_neg(eq, eq, 1 + total);
1688 if (update_constraint(hull->ctx, table,
1689 eq, total, n, 0) < 0)
1690 goto error;
1691 }
1692 }
1693 for (i = 0; i < set->p[s]->n_ineq; ++i) {
1694 isl_int *ineq = set->p[s]->ineq[i];
1695 if (update_constraint(hull->ctx, table, ineq, total, n,
1696 set->p[s]->n_eq == 0) < 0)
1697 goto error;
1698 }
1699 ++n;
1700 }
1701
1702 for (i = 0; i < min_constraints; ++i) {
1703 if (constraints[i].count < n)
1704 continue;
1705 if (!constraints[i].ineq)
1706 continue;
1707 j = isl_basic_set_alloc_inequality(hull);
1708 if (j < 0)
1709 goto error;
1710 isl_seq_cpy(hull->ineq[j], constraints[i].c->row[0], 1 + total);
1711 }
1712
1713 for (s = 0; s < set->n; ++s) {
1714 if (set->p[s]->n_eq)
1715 continue;
1716 if (set->p[s]->n_ineq != hull->n_ineq)
1717 continue;
1718 for (i = 0; i < set->p[s]->n_ineq; ++i) {
1719 isl_bool has;
1720 isl_int *ineq = set->p[s]->ineq[i];
1721 has = has_constraint(hull->ctx, table, ineq, total, n);
1722 if (has < 0)
1723 goto error;
1724 if (!has)
1725 break;
1726 }
1727 if (i == set->p[s]->n_ineq)
1728 *is_hull = 1;
1729 }
1730
1731 isl_hash_table_clear(table);
1732 for (i = 0; i < min_constraints; ++i)
1733 isl_mat_free(constraints[i].c);
1734 free(constraints);
1735 free(table);
1736 return hull;
1737 error:
1738 isl_hash_table_clear(table);
1739 free(table);
1740 if (constraints)
1741 for (i = 0; i < min_constraints; ++i)
1742 isl_mat_free(constraints[i].c);
1743 free(constraints);
1744 return hull;
1745 }
1746
1747 /* Create a template for the convex hull of "set" and fill it up
1748 * obvious facet constraints, if any. If the result happens to
1749 * be the convex hull of "set" then *is_hull is set to 1.
1750 */
proto_hull(__isl_keep isl_set * set,int * is_hull)1751 static __isl_give isl_basic_set *proto_hull(__isl_keep isl_set *set,
1752 int *is_hull)
1753 {
1754 struct isl_basic_set *hull;
1755 unsigned n_ineq;
1756 int i;
1757
1758 n_ineq = 1;
1759 for (i = 0; i < set->n; ++i) {
1760 n_ineq += set->p[i]->n_eq;
1761 n_ineq += set->p[i]->n_ineq;
1762 }
1763 hull = isl_basic_set_alloc_space(isl_space_copy(set->dim), 0, 0, n_ineq);
1764 hull = isl_basic_set_set_rational(hull);
1765 if (!hull)
1766 return NULL;
1767 return common_constraints(hull, set, is_hull);
1768 }
1769
uset_convex_hull_wrap(__isl_take isl_set * set)1770 static __isl_give isl_basic_set *uset_convex_hull_wrap(__isl_take isl_set *set)
1771 {
1772 struct isl_basic_set *hull;
1773 int is_hull;
1774
1775 hull = proto_hull(set, &is_hull);
1776 if (hull && !is_hull) {
1777 if (hull->n_ineq == 0)
1778 hull = initial_hull(hull, set);
1779 hull = extend(hull, set);
1780 }
1781 isl_set_free(set);
1782
1783 return hull;
1784 }
1785
1786 /* Compute the convex hull of a set without any parameters or
1787 * integer divisions. Depending on whether the set is bounded,
1788 * we pass control to the wrapping based convex hull or
1789 * the Fourier-Motzkin elimination based convex hull.
1790 * We also handle a few special cases before checking the boundedness.
1791 */
uset_convex_hull(__isl_take isl_set * set)1792 static __isl_give isl_basic_set *uset_convex_hull(__isl_take isl_set *set)
1793 {
1794 isl_bool bounded;
1795 isl_size dim;
1796 struct isl_basic_set *convex_hull = NULL;
1797 struct isl_basic_set *lin;
1798
1799 dim = isl_set_dim(set, isl_dim_all);
1800 if (dim < 0)
1801 goto error;
1802 if (dim == 0)
1803 return convex_hull_0d(set);
1804
1805 set = isl_set_coalesce(set);
1806 set = isl_set_set_rational(set);
1807
1808 if (!set)
1809 return NULL;
1810 if (set->n == 1) {
1811 convex_hull = isl_basic_set_copy(set->p[0]);
1812 isl_set_free(set);
1813 return convex_hull;
1814 }
1815 if (dim == 1)
1816 return convex_hull_1d(set);
1817
1818 bounded = isl_set_is_bounded(set);
1819 if (bounded < 0)
1820 goto error;
1821 if (bounded && set->ctx->opt->convex == ISL_CONVEX_HULL_WRAP)
1822 return uset_convex_hull_wrap(set);
1823
1824 lin = isl_set_combined_lineality_space(isl_set_copy(set));
1825 if (!lin)
1826 goto error;
1827 if (isl_basic_set_plain_is_universe(lin)) {
1828 isl_set_free(set);
1829 return lin;
1830 }
1831 if (lin->n_eq < dim)
1832 return modulo_lineality(set, lin);
1833 isl_basic_set_free(lin);
1834
1835 return uset_convex_hull_unbounded(set);
1836 error:
1837 isl_set_free(set);
1838 isl_basic_set_free(convex_hull);
1839 return NULL;
1840 }
1841
1842 /* This is the core procedure, where "set" is a "pure" set, i.e.,
1843 * without parameters or divs and where the convex hull of set is
1844 * known to be full-dimensional.
1845 */
uset_convex_hull_wrap_bounded(__isl_take isl_set * set)1846 static __isl_give isl_basic_set *uset_convex_hull_wrap_bounded(
1847 __isl_take isl_set *set)
1848 {
1849 struct isl_basic_set *convex_hull = NULL;
1850 isl_size dim;
1851
1852 dim = isl_set_dim(set, isl_dim_all);
1853 if (dim < 0)
1854 goto error;
1855
1856 if (dim == 0) {
1857 convex_hull = isl_basic_set_universe(isl_space_copy(set->dim));
1858 isl_set_free(set);
1859 convex_hull = isl_basic_set_set_rational(convex_hull);
1860 return convex_hull;
1861 }
1862
1863 set = isl_set_set_rational(set);
1864 set = isl_set_coalesce(set);
1865 if (!set)
1866 goto error;
1867 if (set->n == 1) {
1868 convex_hull = isl_basic_set_copy(set->p[0]);
1869 isl_set_free(set);
1870 convex_hull = isl_basic_map_remove_redundancies(convex_hull);
1871 return convex_hull;
1872 }
1873 if (dim == 1)
1874 return convex_hull_1d(set);
1875
1876 return uset_convex_hull_wrap(set);
1877 error:
1878 isl_set_free(set);
1879 return NULL;
1880 }
1881
1882 /* Compute the convex hull of set "set" with affine hull "affine_hull",
1883 * We first remove the equalities (transforming the set), compute the
1884 * convex hull of the transformed set and then add the equalities back
1885 * (after performing the inverse transformation.
1886 */
modulo_affine_hull(__isl_take isl_set * set,__isl_take isl_basic_set * affine_hull)1887 static __isl_give isl_basic_set *modulo_affine_hull(
1888 __isl_take isl_set *set, __isl_take isl_basic_set *affine_hull)
1889 {
1890 struct isl_mat *T;
1891 struct isl_mat *T2;
1892 struct isl_basic_set *dummy;
1893 struct isl_basic_set *convex_hull;
1894
1895 dummy = isl_basic_set_remove_equalities(
1896 isl_basic_set_copy(affine_hull), &T, &T2);
1897 if (!dummy)
1898 goto error;
1899 isl_basic_set_free(dummy);
1900 set = isl_set_preimage(set, T);
1901 convex_hull = uset_convex_hull(set);
1902 convex_hull = isl_basic_set_preimage(convex_hull, T2);
1903 convex_hull = isl_basic_set_intersect(convex_hull, affine_hull);
1904 return convex_hull;
1905 error:
1906 isl_mat_free(T);
1907 isl_mat_free(T2);
1908 isl_basic_set_free(affine_hull);
1909 isl_set_free(set);
1910 return NULL;
1911 }
1912
1913 /* Return an empty basic map living in the same space as "map".
1914 */
replace_map_by_empty_basic_map(__isl_take isl_map * map)1915 static __isl_give isl_basic_map *replace_map_by_empty_basic_map(
1916 __isl_take isl_map *map)
1917 {
1918 isl_space *space;
1919
1920 space = isl_map_get_space(map);
1921 isl_map_free(map);
1922 return isl_basic_map_empty(space);
1923 }
1924
1925 /* Compute the convex hull of a map.
1926 *
1927 * The implementation was inspired by "Extended Convex Hull" by Fukuda et al.,
1928 * specifically, the wrapping of facets to obtain new facets.
1929 */
isl_map_convex_hull(__isl_take isl_map * map)1930 __isl_give isl_basic_map *isl_map_convex_hull(__isl_take isl_map *map)
1931 {
1932 struct isl_basic_set *bset;
1933 struct isl_basic_map *model = NULL;
1934 struct isl_basic_set *affine_hull = NULL;
1935 struct isl_basic_map *convex_hull = NULL;
1936 struct isl_set *set = NULL;
1937
1938 map = isl_map_detect_equalities(map);
1939 map = isl_map_align_divs_internal(map);
1940 if (!map)
1941 goto error;
1942
1943 if (map->n == 0)
1944 return replace_map_by_empty_basic_map(map);
1945
1946 model = isl_basic_map_copy(map->p[0]);
1947 set = isl_map_underlying_set(map);
1948 if (!set)
1949 goto error;
1950
1951 affine_hull = isl_set_affine_hull(isl_set_copy(set));
1952 if (!affine_hull)
1953 goto error;
1954 if (affine_hull->n_eq != 0)
1955 bset = modulo_affine_hull(set, affine_hull);
1956 else {
1957 isl_basic_set_free(affine_hull);
1958 bset = uset_convex_hull(set);
1959 }
1960
1961 convex_hull = isl_basic_map_overlying_set(bset, model);
1962 if (!convex_hull)
1963 return NULL;
1964
1965 ISL_F_SET(convex_hull, ISL_BASIC_MAP_NO_IMPLICIT);
1966 ISL_F_SET(convex_hull, ISL_BASIC_MAP_ALL_EQUALITIES);
1967 ISL_F_CLR(convex_hull, ISL_BASIC_MAP_RATIONAL);
1968 return convex_hull;
1969 error:
1970 isl_set_free(set);
1971 isl_basic_map_free(model);
1972 return NULL;
1973 }
1974
isl_set_convex_hull(__isl_take isl_set * set)1975 __isl_give isl_basic_set *isl_set_convex_hull(__isl_take isl_set *set)
1976 {
1977 return bset_from_bmap(isl_map_convex_hull(set_to_map(set)));
1978 }
1979
isl_map_polyhedral_hull(__isl_take isl_map * map)1980 __isl_give isl_basic_map *isl_map_polyhedral_hull(__isl_take isl_map *map)
1981 {
1982 isl_basic_map *hull;
1983
1984 hull = isl_map_convex_hull(map);
1985 return isl_basic_map_remove_divs(hull);
1986 }
1987
isl_set_polyhedral_hull(__isl_take isl_set * set)1988 __isl_give isl_basic_set *isl_set_polyhedral_hull(__isl_take isl_set *set)
1989 {
1990 return bset_from_bmap(isl_map_polyhedral_hull(set_to_map(set)));
1991 }
1992
1993 struct sh_data_entry {
1994 struct isl_hash_table *table;
1995 struct isl_tab *tab;
1996 };
1997
1998 /* Holds the data needed during the simple hull computation.
1999 * In particular,
2000 * n the number of basic sets in the original set
2001 * hull_table a hash table of already computed constraints
2002 * in the simple hull
2003 * p for each basic set,
2004 * table a hash table of the constraints
2005 * tab the tableau corresponding to the basic set
2006 */
2007 struct sh_data {
2008 struct isl_ctx *ctx;
2009 unsigned n;
2010 struct isl_hash_table *hull_table;
2011 struct sh_data_entry p[1];
2012 };
2013
sh_data_free(struct sh_data * data)2014 static void sh_data_free(struct sh_data *data)
2015 {
2016 int i;
2017
2018 if (!data)
2019 return;
2020 isl_hash_table_free(data->ctx, data->hull_table);
2021 for (i = 0; i < data->n; ++i) {
2022 isl_hash_table_free(data->ctx, data->p[i].table);
2023 isl_tab_free(data->p[i].tab);
2024 }
2025 free(data);
2026 }
2027
2028 struct ineq_cmp_data {
2029 unsigned len;
2030 isl_int *p;
2031 };
2032
has_ineq(const void * entry,const void * val)2033 static isl_bool has_ineq(const void *entry, const void *val)
2034 {
2035 isl_int *row = (isl_int *)entry;
2036 struct ineq_cmp_data *v = (struct ineq_cmp_data *)val;
2037
2038 return isl_bool_ok(isl_seq_eq(row + 1, v->p + 1, v->len) ||
2039 isl_seq_is_neg(row + 1, v->p + 1, v->len));
2040 }
2041
hash_ineq(struct isl_ctx * ctx,struct isl_hash_table * table,isl_int * ineq,unsigned len)2042 static int hash_ineq(struct isl_ctx *ctx, struct isl_hash_table *table,
2043 isl_int *ineq, unsigned len)
2044 {
2045 uint32_t c_hash;
2046 struct ineq_cmp_data v;
2047 struct isl_hash_table_entry *entry;
2048
2049 v.len = len;
2050 v.p = ineq;
2051 c_hash = isl_seq_get_hash(ineq + 1, len);
2052 entry = isl_hash_table_find(ctx, table, c_hash, has_ineq, &v, 1);
2053 if (!entry)
2054 return - 1;
2055 entry->data = ineq;
2056 return 0;
2057 }
2058
2059 /* Fill hash table "table" with the constraints of "bset".
2060 * Equalities are added as two inequalities.
2061 * The value in the hash table is a pointer to the (in)equality of "bset".
2062 */
hash_basic_set(struct isl_hash_table * table,__isl_keep isl_basic_set * bset)2063 static isl_stat hash_basic_set(struct isl_hash_table *table,
2064 __isl_keep isl_basic_set *bset)
2065 {
2066 int i, j;
2067 isl_size dim = isl_basic_set_dim(bset, isl_dim_all);
2068
2069 if (dim < 0)
2070 return isl_stat_error;
2071 for (i = 0; i < bset->n_eq; ++i) {
2072 for (j = 0; j < 2; ++j) {
2073 isl_seq_neg(bset->eq[i], bset->eq[i], 1 + dim);
2074 if (hash_ineq(bset->ctx, table, bset->eq[i], dim) < 0)
2075 return isl_stat_error;
2076 }
2077 }
2078 for (i = 0; i < bset->n_ineq; ++i) {
2079 if (hash_ineq(bset->ctx, table, bset->ineq[i], dim) < 0)
2080 return isl_stat_error;
2081 }
2082 return isl_stat_ok;
2083 }
2084
sh_data_alloc(__isl_keep isl_set * set,unsigned n_ineq)2085 static struct sh_data *sh_data_alloc(__isl_keep isl_set *set, unsigned n_ineq)
2086 {
2087 struct sh_data *data;
2088 int i;
2089
2090 data = isl_calloc(set->ctx, struct sh_data,
2091 sizeof(struct sh_data) +
2092 (set->n - 1) * sizeof(struct sh_data_entry));
2093 if (!data)
2094 return NULL;
2095 data->ctx = set->ctx;
2096 data->n = set->n;
2097 data->hull_table = isl_hash_table_alloc(set->ctx, n_ineq);
2098 if (!data->hull_table)
2099 goto error;
2100 for (i = 0; i < set->n; ++i) {
2101 data->p[i].table = isl_hash_table_alloc(set->ctx,
2102 2 * set->p[i]->n_eq + set->p[i]->n_ineq);
2103 if (!data->p[i].table)
2104 goto error;
2105 if (hash_basic_set(data->p[i].table, set->p[i]) < 0)
2106 goto error;
2107 }
2108 return data;
2109 error:
2110 sh_data_free(data);
2111 return NULL;
2112 }
2113
2114 /* Check if inequality "ineq" is a bound for basic set "j" or if
2115 * it can be relaxed (by increasing the constant term) to become
2116 * a bound for that basic set. In the latter case, the constant
2117 * term is updated.
2118 * Relaxation of the constant term is only allowed if "shift" is set.
2119 *
2120 * Return 1 if "ineq" is a bound
2121 * 0 if "ineq" may attain arbitrarily small values on basic set "j"
2122 * -1 if some error occurred
2123 */
is_bound(struct sh_data * data,__isl_keep isl_set * set,int j,isl_int * ineq,int shift)2124 static int is_bound(struct sh_data *data, __isl_keep isl_set *set, int j,
2125 isl_int *ineq, int shift)
2126 {
2127 enum isl_lp_result res;
2128 isl_int opt;
2129
2130 if (!data->p[j].tab) {
2131 data->p[j].tab = isl_tab_from_basic_set(set->p[j], 0);
2132 if (!data->p[j].tab)
2133 return -1;
2134 }
2135
2136 isl_int_init(opt);
2137
2138 res = isl_tab_min(data->p[j].tab, ineq, data->ctx->one,
2139 &opt, NULL, 0);
2140 if (res == isl_lp_ok && isl_int_is_neg(opt)) {
2141 if (shift)
2142 isl_int_sub(ineq[0], ineq[0], opt);
2143 else
2144 res = isl_lp_unbounded;
2145 }
2146
2147 isl_int_clear(opt);
2148
2149 return (res == isl_lp_ok || res == isl_lp_empty) ? 1 :
2150 res == isl_lp_unbounded ? 0 : -1;
2151 }
2152
2153 /* Set the constant term of "ineq" to the maximum of those of the constraints
2154 * in the basic sets of "set" following "i" that are parallel to "ineq".
2155 * That is, if any of the basic sets of "set" following "i" have a more
2156 * relaxed copy of "ineq", then replace "ineq" by the most relaxed copy.
2157 * "c_hash" is the hash value of the linear part of "ineq".
2158 * "v" has been set up for use by has_ineq.
2159 *
2160 * Note that the two inequality constraints corresponding to an equality are
2161 * represented by the same inequality constraint in data->p[j].table
2162 * (but with different hash values). This means the constraint (or at
2163 * least its constant term) may need to be temporarily negated to get
2164 * the actually hashed constraint.
2165 */
set_max_constant_term(struct sh_data * data,__isl_keep isl_set * set,int i,isl_int * ineq,uint32_t c_hash,struct ineq_cmp_data * v)2166 static isl_stat set_max_constant_term(struct sh_data *data,
2167 __isl_keep isl_set *set,
2168 int i, isl_int *ineq, uint32_t c_hash, struct ineq_cmp_data *v)
2169 {
2170 int j;
2171 isl_ctx *ctx;
2172 struct isl_hash_table_entry *entry;
2173
2174 ctx = isl_set_get_ctx(set);
2175 for (j = i + 1; j < set->n; ++j) {
2176 int neg;
2177 isl_int *ineq_j;
2178
2179 entry = isl_hash_table_find(ctx, data->p[j].table,
2180 c_hash, &has_ineq, v, 0);
2181 if (!entry)
2182 return isl_stat_error;
2183 if (entry == isl_hash_table_entry_none)
2184 continue;
2185
2186 ineq_j = entry->data;
2187 neg = isl_seq_is_neg(ineq_j + 1, ineq + 1, v->len);
2188 if (neg)
2189 isl_int_neg(ineq_j[0], ineq_j[0]);
2190 if (isl_int_gt(ineq_j[0], ineq[0]))
2191 isl_int_set(ineq[0], ineq_j[0]);
2192 if (neg)
2193 isl_int_neg(ineq_j[0], ineq_j[0]);
2194 }
2195
2196 return isl_stat_ok;
2197 }
2198
2199 /* Check if inequality "ineq" from basic set "i" is or can be relaxed to
2200 * become a bound on the whole set. If so, add the (relaxed) inequality
2201 * to "hull". Relaxation is only allowed if "shift" is set.
2202 *
2203 * We first check if "hull" already contains a translate of the inequality.
2204 * If so, we are done.
2205 * Then, we check if any of the previous basic sets contains a translate
2206 * of the inequality. If so, then we have already considered this
2207 * inequality and we are done.
2208 * Otherwise, for each basic set other than "i", we check if the inequality
2209 * is a bound on the basic set, but first replace the constant term
2210 * by the maximal value of any translate of the inequality in any
2211 * of the following basic sets.
2212 * For previous basic sets, we know that they do not contain a translate
2213 * of the inequality, so we directly call is_bound.
2214 * For following basic sets, we first check if a translate of the
2215 * inequality appears in its description. If so, the constant term
2216 * of the inequality has already been updated with respect to this
2217 * translate and the inequality is therefore known to be a bound
2218 * of this basic set.
2219 */
add_bound(__isl_take isl_basic_set * hull,struct sh_data * data,__isl_keep isl_set * set,int i,isl_int * ineq,int shift)2220 static __isl_give isl_basic_set *add_bound(__isl_take isl_basic_set *hull,
2221 struct sh_data *data, __isl_keep isl_set *set, int i, isl_int *ineq,
2222 int shift)
2223 {
2224 uint32_t c_hash;
2225 struct ineq_cmp_data v;
2226 struct isl_hash_table_entry *entry;
2227 int j, k;
2228 isl_size total;
2229
2230 total = isl_basic_set_dim(hull, isl_dim_all);
2231 if (total < 0)
2232 return isl_basic_set_free(hull);
2233
2234 v.len = total;
2235 v.p = ineq;
2236 c_hash = isl_seq_get_hash(ineq + 1, v.len);
2237
2238 entry = isl_hash_table_find(hull->ctx, data->hull_table, c_hash,
2239 has_ineq, &v, 0);
2240 if (!entry)
2241 return isl_basic_set_free(hull);
2242 if (entry != isl_hash_table_entry_none)
2243 return hull;
2244
2245 for (j = 0; j < i; ++j) {
2246 entry = isl_hash_table_find(hull->ctx, data->p[j].table,
2247 c_hash, has_ineq, &v, 0);
2248 if (!entry)
2249 return isl_basic_set_free(hull);
2250 if (entry != isl_hash_table_entry_none)
2251 break;
2252 }
2253 if (j < i)
2254 return hull;
2255
2256 k = isl_basic_set_alloc_inequality(hull);
2257 if (k < 0)
2258 goto error;
2259 isl_seq_cpy(hull->ineq[k], ineq, 1 + v.len);
2260
2261 if (set_max_constant_term(data, set, i, hull->ineq[k], c_hash, &v) < 0)
2262 goto error;
2263 for (j = 0; j < i; ++j) {
2264 int bound;
2265 bound = is_bound(data, set, j, hull->ineq[k], shift);
2266 if (bound < 0)
2267 goto error;
2268 if (!bound)
2269 break;
2270 }
2271 if (j < i)
2272 return isl_basic_set_free_inequality(hull, 1);
2273
2274 for (j = i + 1; j < set->n; ++j) {
2275 int bound;
2276 entry = isl_hash_table_find(hull->ctx, data->p[j].table,
2277 c_hash, has_ineq, &v, 0);
2278 if (!entry)
2279 return isl_basic_set_free(hull);
2280 if (entry != isl_hash_table_entry_none)
2281 continue;
2282 bound = is_bound(data, set, j, hull->ineq[k], shift);
2283 if (bound < 0)
2284 goto error;
2285 if (!bound)
2286 break;
2287 }
2288 if (j < set->n)
2289 return isl_basic_set_free_inequality(hull, 1);
2290
2291 entry = isl_hash_table_find(hull->ctx, data->hull_table, c_hash,
2292 has_ineq, &v, 1);
2293 if (!entry)
2294 goto error;
2295 entry->data = hull->ineq[k];
2296
2297 return hull;
2298 error:
2299 isl_basic_set_free(hull);
2300 return NULL;
2301 }
2302
2303 /* Check if any inequality from basic set "i" is or can be relaxed to
2304 * become a bound on the whole set. If so, add the (relaxed) inequality
2305 * to "hull". Relaxation is only allowed if "shift" is set.
2306 */
add_bounds(__isl_take isl_basic_set * bset,struct sh_data * data,__isl_keep isl_set * set,int i,int shift)2307 static __isl_give isl_basic_set *add_bounds(__isl_take isl_basic_set *bset,
2308 struct sh_data *data, __isl_keep isl_set *set, int i, int shift)
2309 {
2310 int j, k;
2311 isl_size dim = isl_basic_set_dim(bset, isl_dim_all);
2312
2313 if (dim < 0)
2314 return isl_basic_set_free(bset);
2315
2316 for (j = 0; j < set->p[i]->n_eq; ++j) {
2317 for (k = 0; k < 2; ++k) {
2318 isl_seq_neg(set->p[i]->eq[j], set->p[i]->eq[j], 1+dim);
2319 bset = add_bound(bset, data, set, i, set->p[i]->eq[j],
2320 shift);
2321 }
2322 }
2323 for (j = 0; j < set->p[i]->n_ineq; ++j)
2324 bset = add_bound(bset, data, set, i, set->p[i]->ineq[j], shift);
2325 return bset;
2326 }
2327
2328 /* Compute a superset of the convex hull of set that is described
2329 * by only (translates of) the constraints in the constituents of set.
2330 * Translation is only allowed if "shift" is set.
2331 */
uset_simple_hull(__isl_take isl_set * set,int shift)2332 static __isl_give isl_basic_set *uset_simple_hull(__isl_take isl_set *set,
2333 int shift)
2334 {
2335 struct sh_data *data = NULL;
2336 struct isl_basic_set *hull = NULL;
2337 unsigned n_ineq;
2338 int i;
2339
2340 if (!set)
2341 return NULL;
2342
2343 n_ineq = 0;
2344 for (i = 0; i < set->n; ++i) {
2345 if (!set->p[i])
2346 goto error;
2347 n_ineq += 2 * set->p[i]->n_eq + set->p[i]->n_ineq;
2348 }
2349
2350 hull = isl_basic_set_alloc_space(isl_space_copy(set->dim), 0, 0, n_ineq);
2351 if (!hull)
2352 goto error;
2353
2354 data = sh_data_alloc(set, n_ineq);
2355 if (!data)
2356 goto error;
2357
2358 for (i = 0; i < set->n; ++i)
2359 hull = add_bounds(hull, data, set, i, shift);
2360
2361 sh_data_free(data);
2362 isl_set_free(set);
2363
2364 return hull;
2365 error:
2366 sh_data_free(data);
2367 isl_basic_set_free(hull);
2368 isl_set_free(set);
2369 return NULL;
2370 }
2371
2372 /* Compute a superset of the convex hull of map that is described
2373 * by only (translates of) the constraints in the constituents of map.
2374 * Handle trivial cases where map is NULL or contains at most one disjunct.
2375 */
map_simple_hull_trivial(__isl_take isl_map * map)2376 static __isl_give isl_basic_map *map_simple_hull_trivial(
2377 __isl_take isl_map *map)
2378 {
2379 isl_basic_map *hull;
2380
2381 if (!map)
2382 return NULL;
2383 if (map->n == 0)
2384 return replace_map_by_empty_basic_map(map);
2385
2386 hull = isl_basic_map_copy(map->p[0]);
2387 isl_map_free(map);
2388 return hull;
2389 }
2390
2391 /* Return a copy of the simple hull cached inside "map".
2392 * "shift" determines whether to return the cached unshifted or shifted
2393 * simple hull.
2394 */
cached_simple_hull(__isl_take isl_map * map,int shift)2395 static __isl_give isl_basic_map *cached_simple_hull(__isl_take isl_map *map,
2396 int shift)
2397 {
2398 isl_basic_map *hull;
2399
2400 hull = isl_basic_map_copy(map->cached_simple_hull[shift]);
2401 isl_map_free(map);
2402
2403 return hull;
2404 }
2405
2406 /* Compute a superset of the convex hull of map that is described
2407 * by only (translates of) the constraints in the constituents of map.
2408 * Translation is only allowed if "shift" is set.
2409 *
2410 * The constraints are sorted while removing redundant constraints
2411 * in order to indicate a preference of which constraints should
2412 * be preserved. In particular, pairs of constraints that are
2413 * sorted together are preferred to either both be preserved
2414 * or both be removed. The sorting is performed inside
2415 * isl_basic_map_remove_redundancies.
2416 *
2417 * The result of the computation is stored in map->cached_simple_hull[shift]
2418 * such that it can be reused in subsequent calls. The cache is cleared
2419 * whenever the map is modified (in isl_map_cow).
2420 * Note that the results need to be stored in the input map for there
2421 * to be any chance that they may get reused. In particular, they
2422 * are stored in a copy of the input map that is saved before
2423 * the integer division alignment.
2424 */
map_simple_hull(__isl_take isl_map * map,int shift)2425 static __isl_give isl_basic_map *map_simple_hull(__isl_take isl_map *map,
2426 int shift)
2427 {
2428 struct isl_set *set = NULL;
2429 struct isl_basic_map *model = NULL;
2430 struct isl_basic_map *hull;
2431 struct isl_basic_map *affine_hull;
2432 struct isl_basic_set *bset = NULL;
2433 isl_map *input;
2434
2435 if (!map || map->n <= 1)
2436 return map_simple_hull_trivial(map);
2437
2438 if (map->cached_simple_hull[shift])
2439 return cached_simple_hull(map, shift);
2440
2441 map = isl_map_detect_equalities(map);
2442 if (!map || map->n <= 1)
2443 return map_simple_hull_trivial(map);
2444 affine_hull = isl_map_affine_hull(isl_map_copy(map));
2445 input = isl_map_copy(map);
2446 map = isl_map_align_divs_internal(map);
2447 model = map ? isl_basic_map_copy(map->p[0]) : NULL;
2448
2449 set = isl_map_underlying_set(map);
2450
2451 bset = uset_simple_hull(set, shift);
2452
2453 hull = isl_basic_map_overlying_set(bset, model);
2454
2455 hull = isl_basic_map_intersect(hull, affine_hull);
2456 hull = isl_basic_map_remove_redundancies(hull);
2457
2458 if (hull) {
2459 ISL_F_SET(hull, ISL_BASIC_MAP_NO_IMPLICIT);
2460 ISL_F_SET(hull, ISL_BASIC_MAP_ALL_EQUALITIES);
2461 }
2462
2463 hull = isl_basic_map_finalize(hull);
2464 if (input)
2465 input->cached_simple_hull[shift] = isl_basic_map_copy(hull);
2466 isl_map_free(input);
2467
2468 return hull;
2469 }
2470
2471 /* Compute a superset of the convex hull of map that is described
2472 * by only translates of the constraints in the constituents of map.
2473 */
isl_map_simple_hull(__isl_take isl_map * map)2474 __isl_give isl_basic_map *isl_map_simple_hull(__isl_take isl_map *map)
2475 {
2476 return map_simple_hull(map, 1);
2477 }
2478
isl_set_simple_hull(__isl_take isl_set * set)2479 __isl_give isl_basic_set *isl_set_simple_hull(__isl_take isl_set *set)
2480 {
2481 return bset_from_bmap(isl_map_simple_hull(set_to_map(set)));
2482 }
2483
2484 /* Compute a superset of the convex hull of map that is described
2485 * by only the constraints in the constituents of map.
2486 */
isl_map_unshifted_simple_hull(__isl_take isl_map * map)2487 __isl_give isl_basic_map *isl_map_unshifted_simple_hull(
2488 __isl_take isl_map *map)
2489 {
2490 return map_simple_hull(map, 0);
2491 }
2492
isl_set_unshifted_simple_hull(__isl_take isl_set * set)2493 __isl_give isl_basic_set *isl_set_unshifted_simple_hull(
2494 __isl_take isl_set *set)
2495 {
2496 return isl_map_unshifted_simple_hull(set);
2497 }
2498
2499 /* Drop all inequalities from "bmap1" that do not also appear in "bmap2".
2500 * A constraint that appears with different constant terms
2501 * in "bmap1" and "bmap2" is also kept, with the least restrictive
2502 * (i.e., greatest) constant term.
2503 * "bmap1" and "bmap2" are assumed to have the same (known)
2504 * integer divisions.
2505 * The constraints of both "bmap1" and "bmap2" are assumed
2506 * to have been sorted using isl_basic_map_sort_constraints.
2507 *
2508 * Run through the inequality constraints of "bmap1" and "bmap2"
2509 * in sorted order.
2510 * Each constraint of "bmap1" without a matching constraint in "bmap2"
2511 * is removed.
2512 * If a match is found, the constraint is kept. If needed, the constant
2513 * term of the constraint is adjusted.
2514 */
select_shared_inequalities(__isl_take isl_basic_map * bmap1,__isl_keep isl_basic_map * bmap2)2515 static __isl_give isl_basic_map *select_shared_inequalities(
2516 __isl_take isl_basic_map *bmap1, __isl_keep isl_basic_map *bmap2)
2517 {
2518 int i1, i2;
2519
2520 bmap1 = isl_basic_map_cow(bmap1);
2521 if (!bmap1 || !bmap2)
2522 return isl_basic_map_free(bmap1);
2523
2524 i1 = bmap1->n_ineq - 1;
2525 i2 = bmap2->n_ineq - 1;
2526 while (bmap1 && i1 >= 0 && i2 >= 0) {
2527 int cmp;
2528
2529 cmp = isl_basic_map_constraint_cmp(bmap1, bmap1->ineq[i1],
2530 bmap2->ineq[i2]);
2531 if (cmp < 0) {
2532 --i2;
2533 continue;
2534 }
2535 if (cmp > 0) {
2536 if (isl_basic_map_drop_inequality(bmap1, i1) < 0)
2537 bmap1 = isl_basic_map_free(bmap1);
2538 --i1;
2539 continue;
2540 }
2541 if (isl_int_lt(bmap1->ineq[i1][0], bmap2->ineq[i2][0]))
2542 isl_int_set(bmap1->ineq[i1][0], bmap2->ineq[i2][0]);
2543 --i1;
2544 --i2;
2545 }
2546 for (; i1 >= 0; --i1)
2547 if (isl_basic_map_drop_inequality(bmap1, i1) < 0)
2548 bmap1 = isl_basic_map_free(bmap1);
2549
2550 return bmap1;
2551 }
2552
2553 /* Drop all equalities from "bmap1" that do not also appear in "bmap2".
2554 * "bmap1" and "bmap2" are assumed to have the same (known)
2555 * integer divisions.
2556 *
2557 * Run through the equality constraints of "bmap1" and "bmap2".
2558 * Each constraint of "bmap1" without a matching constraint in "bmap2"
2559 * is removed.
2560 */
select_shared_equalities(__isl_take isl_basic_map * bmap1,__isl_keep isl_basic_map * bmap2)2561 static __isl_give isl_basic_map *select_shared_equalities(
2562 __isl_take isl_basic_map *bmap1, __isl_keep isl_basic_map *bmap2)
2563 {
2564 int i1, i2;
2565 isl_size total;
2566
2567 bmap1 = isl_basic_map_cow(bmap1);
2568 total = isl_basic_map_dim(bmap1, isl_dim_all);
2569 if (total < 0 || !bmap2)
2570 return isl_basic_map_free(bmap1);
2571
2572 i1 = bmap1->n_eq - 1;
2573 i2 = bmap2->n_eq - 1;
2574 while (bmap1 && i1 >= 0 && i2 >= 0) {
2575 int last1, last2;
2576
2577 last1 = isl_seq_last_non_zero(bmap1->eq[i1] + 1, total);
2578 last2 = isl_seq_last_non_zero(bmap2->eq[i2] + 1, total);
2579 if (last1 > last2) {
2580 --i2;
2581 continue;
2582 }
2583 if (last1 < last2) {
2584 if (isl_basic_map_drop_equality(bmap1, i1) < 0)
2585 bmap1 = isl_basic_map_free(bmap1);
2586 --i1;
2587 continue;
2588 }
2589 if (!isl_seq_eq(bmap1->eq[i1], bmap2->eq[i2], 1 + total)) {
2590 if (isl_basic_map_drop_equality(bmap1, i1) < 0)
2591 bmap1 = isl_basic_map_free(bmap1);
2592 }
2593 --i1;
2594 --i2;
2595 }
2596 for (; i1 >= 0; --i1)
2597 if (isl_basic_map_drop_equality(bmap1, i1) < 0)
2598 bmap1 = isl_basic_map_free(bmap1);
2599
2600 return bmap1;
2601 }
2602
2603 /* Compute a superset of "bmap1" and "bmap2" that is described
2604 * by only the constraints that appear in both "bmap1" and "bmap2".
2605 *
2606 * First drop constraints that involve unknown integer divisions
2607 * since it is not trivial to check whether two such integer divisions
2608 * in different basic maps are the same.
2609 * Then align the remaining (known) divs and sort the constraints.
2610 * Finally drop all inequalities and equalities from "bmap1" that
2611 * do not also appear in "bmap2".
2612 */
isl_basic_map_plain_unshifted_simple_hull(__isl_take isl_basic_map * bmap1,__isl_take isl_basic_map * bmap2)2613 __isl_give isl_basic_map *isl_basic_map_plain_unshifted_simple_hull(
2614 __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
2615 {
2616 if (isl_basic_map_check_equal_space(bmap1, bmap2) < 0)
2617 goto error;
2618
2619 bmap1 = isl_basic_map_drop_constraints_involving_unknown_divs(bmap1);
2620 bmap2 = isl_basic_map_drop_constraints_involving_unknown_divs(bmap2);
2621 bmap2 = isl_basic_map_align_divs(bmap2, bmap1);
2622 bmap1 = isl_basic_map_align_divs(bmap1, bmap2);
2623 bmap1 = isl_basic_map_sort_constraints(bmap1);
2624 bmap2 = isl_basic_map_sort_constraints(bmap2);
2625
2626 bmap1 = select_shared_inequalities(bmap1, bmap2);
2627 bmap1 = select_shared_equalities(bmap1, bmap2);
2628
2629 isl_basic_map_free(bmap2);
2630 bmap1 = isl_basic_map_finalize(bmap1);
2631 return bmap1;
2632 error:
2633 isl_basic_map_free(bmap1);
2634 isl_basic_map_free(bmap2);
2635 return NULL;
2636 }
2637
2638 /* Compute a superset of the convex hull of "map" that is described
2639 * by only the constraints in the constituents of "map".
2640 * In particular, the result is composed of constraints that appear
2641 * in each of the basic maps of "map"
2642 *
2643 * Constraints that involve unknown integer divisions are dropped
2644 * since it is not trivial to check whether two such integer divisions
2645 * in different basic maps are the same.
2646 *
2647 * The hull is initialized from the first basic map and then
2648 * updated with respect to the other basic maps in turn.
2649 */
isl_map_plain_unshifted_simple_hull(__isl_take isl_map * map)2650 __isl_give isl_basic_map *isl_map_plain_unshifted_simple_hull(
2651 __isl_take isl_map *map)
2652 {
2653 int i;
2654 isl_basic_map *hull;
2655
2656 if (!map)
2657 return NULL;
2658 if (map->n <= 1)
2659 return map_simple_hull_trivial(map);
2660 map = isl_map_drop_constraints_involving_unknown_divs(map);
2661 hull = isl_basic_map_copy(map->p[0]);
2662 for (i = 1; i < map->n; ++i) {
2663 isl_basic_map *bmap_i;
2664
2665 bmap_i = isl_basic_map_copy(map->p[i]);
2666 hull = isl_basic_map_plain_unshifted_simple_hull(hull, bmap_i);
2667 }
2668
2669 isl_map_free(map);
2670 return hull;
2671 }
2672
2673 /* Compute a superset of the convex hull of "set" that is described
2674 * by only the constraints in the constituents of "set".
2675 * In particular, the result is composed of constraints that appear
2676 * in each of the basic sets of "set"
2677 */
isl_set_plain_unshifted_simple_hull(__isl_take isl_set * set)2678 __isl_give isl_basic_set *isl_set_plain_unshifted_simple_hull(
2679 __isl_take isl_set *set)
2680 {
2681 return isl_map_plain_unshifted_simple_hull(set);
2682 }
2683
2684 /* Check if "ineq" is a bound on "set" and, if so, add it to "hull".
2685 *
2686 * For each basic set in "set", we first check if the basic set
2687 * contains a translate of "ineq". If this translate is more relaxed,
2688 * then we assume that "ineq" is not a bound on this basic set.
2689 * Otherwise, we know that it is a bound.
2690 * If the basic set does not contain a translate of "ineq", then
2691 * we call is_bound to perform the test.
2692 */
add_bound_from_constraint(__isl_take isl_basic_set * hull,struct sh_data * data,__isl_keep isl_set * set,isl_int * ineq)2693 static __isl_give isl_basic_set *add_bound_from_constraint(
2694 __isl_take isl_basic_set *hull, struct sh_data *data,
2695 __isl_keep isl_set *set, isl_int *ineq)
2696 {
2697 int i, k;
2698 isl_ctx *ctx;
2699 uint32_t c_hash;
2700 struct ineq_cmp_data v;
2701 isl_size total;
2702
2703 total = isl_basic_set_dim(hull, isl_dim_all);
2704 if (total < 0 || !set)
2705 return isl_basic_set_free(hull);
2706
2707 v.len = total;
2708 v.p = ineq;
2709 c_hash = isl_seq_get_hash(ineq + 1, v.len);
2710
2711 ctx = isl_basic_set_get_ctx(hull);
2712 for (i = 0; i < set->n; ++i) {
2713 int bound;
2714 struct isl_hash_table_entry *entry;
2715
2716 entry = isl_hash_table_find(ctx, data->p[i].table,
2717 c_hash, &has_ineq, &v, 0);
2718 if (!entry)
2719 return isl_basic_set_free(hull);
2720 if (entry != isl_hash_table_entry_none) {
2721 isl_int *ineq_i = entry->data;
2722 int neg, more_relaxed;
2723
2724 neg = isl_seq_is_neg(ineq_i + 1, ineq + 1, v.len);
2725 if (neg)
2726 isl_int_neg(ineq_i[0], ineq_i[0]);
2727 more_relaxed = isl_int_gt(ineq_i[0], ineq[0]);
2728 if (neg)
2729 isl_int_neg(ineq_i[0], ineq_i[0]);
2730 if (more_relaxed)
2731 break;
2732 else
2733 continue;
2734 }
2735 bound = is_bound(data, set, i, ineq, 0);
2736 if (bound < 0)
2737 return isl_basic_set_free(hull);
2738 if (!bound)
2739 break;
2740 }
2741 if (i < set->n)
2742 return hull;
2743
2744 k = isl_basic_set_alloc_inequality(hull);
2745 if (k < 0)
2746 return isl_basic_set_free(hull);
2747 isl_seq_cpy(hull->ineq[k], ineq, 1 + v.len);
2748
2749 return hull;
2750 }
2751
2752 /* Compute a superset of the convex hull of "set" that is described
2753 * by only some of the "n_ineq" constraints in the list "ineq", where "set"
2754 * has no parameters or integer divisions.
2755 *
2756 * The inequalities in "ineq" are assumed to have been sorted such
2757 * that constraints with the same linear part appear together and
2758 * that among constraints with the same linear part, those with
2759 * smaller constant term appear first.
2760 *
2761 * We reuse the same data structure that is used by uset_simple_hull,
2762 * but we do not need the hull table since we will not consider the
2763 * same constraint more than once. We therefore allocate it with zero size.
2764 *
2765 * We run through the constraints and try to add them one by one,
2766 * skipping identical constraints. If we have added a constraint and
2767 * the next constraint is a more relaxed translate, then we skip this
2768 * next constraint as well.
2769 */
uset_unshifted_simple_hull_from_constraints(__isl_take isl_set * set,int n_ineq,isl_int ** ineq)2770 static __isl_give isl_basic_set *uset_unshifted_simple_hull_from_constraints(
2771 __isl_take isl_set *set, int n_ineq, isl_int **ineq)
2772 {
2773 int i;
2774 int last_added = 0;
2775 struct sh_data *data = NULL;
2776 isl_basic_set *hull = NULL;
2777 isl_size dim;
2778
2779 hull = isl_basic_set_alloc_space(isl_set_get_space(set), 0, 0, n_ineq);
2780 if (!hull)
2781 goto error;
2782
2783 data = sh_data_alloc(set, 0);
2784 if (!data)
2785 goto error;
2786
2787 dim = isl_set_dim(set, isl_dim_set);
2788 if (dim < 0)
2789 goto error;
2790 for (i = 0; i < n_ineq; ++i) {
2791 int hull_n_ineq = hull->n_ineq;
2792 int parallel;
2793
2794 parallel = i > 0 && isl_seq_eq(ineq[i - 1] + 1, ineq[i] + 1,
2795 dim);
2796 if (parallel &&
2797 (last_added || isl_int_eq(ineq[i - 1][0], ineq[i][0])))
2798 continue;
2799 hull = add_bound_from_constraint(hull, data, set, ineq[i]);
2800 if (!hull)
2801 goto error;
2802 last_added = hull->n_ineq > hull_n_ineq;
2803 }
2804
2805 sh_data_free(data);
2806 isl_set_free(set);
2807 return hull;
2808 error:
2809 sh_data_free(data);
2810 isl_set_free(set);
2811 isl_basic_set_free(hull);
2812 return NULL;
2813 }
2814
2815 /* Collect pointers to all the inequalities in the elements of "list"
2816 * in "ineq". For equalities, store both a pointer to the equality and
2817 * a pointer to its opposite, which is first copied to "mat".
2818 * "ineq" and "mat" are assumed to have been preallocated to the right size
2819 * (the number of inequalities + 2 times the number of equalites and
2820 * the number of equalities, respectively).
2821 */
collect_inequalities(__isl_take isl_mat * mat,__isl_keep isl_basic_set_list * list,isl_int ** ineq)2822 static __isl_give isl_mat *collect_inequalities(__isl_take isl_mat *mat,
2823 __isl_keep isl_basic_set_list *list, isl_int **ineq)
2824 {
2825 int i, j, n_eq, n_ineq;
2826 isl_size n;
2827
2828 n = isl_basic_set_list_n_basic_set(list);
2829 if (!mat || n < 0)
2830 return isl_mat_free(mat);
2831
2832 n_eq = 0;
2833 n_ineq = 0;
2834 for (i = 0; i < n; ++i) {
2835 isl_basic_set *bset;
2836 bset = isl_basic_set_list_get_basic_set(list, i);
2837 if (!bset)
2838 return isl_mat_free(mat);
2839 for (j = 0; j < bset->n_eq; ++j) {
2840 ineq[n_ineq++] = mat->row[n_eq];
2841 ineq[n_ineq++] = bset->eq[j];
2842 isl_seq_neg(mat->row[n_eq++], bset->eq[j], mat->n_col);
2843 }
2844 for (j = 0; j < bset->n_ineq; ++j)
2845 ineq[n_ineq++] = bset->ineq[j];
2846 isl_basic_set_free(bset);
2847 }
2848
2849 return mat;
2850 }
2851
2852 /* Comparison routine for use as an isl_sort callback.
2853 *
2854 * Constraints with the same linear part are sorted together and
2855 * among constraints with the same linear part, those with smaller
2856 * constant term are sorted first.
2857 */
cmp_ineq(const void * a,const void * b,void * arg)2858 static int cmp_ineq(const void *a, const void *b, void *arg)
2859 {
2860 unsigned dim = *(unsigned *) arg;
2861 isl_int * const *ineq1 = a;
2862 isl_int * const *ineq2 = b;
2863 int cmp;
2864
2865 cmp = isl_seq_cmp((*ineq1) + 1, (*ineq2) + 1, dim);
2866 if (cmp != 0)
2867 return cmp;
2868 return isl_int_cmp((*ineq1)[0], (*ineq2)[0]);
2869 }
2870
2871 /* Compute a superset of the convex hull of "set" that is described
2872 * by only constraints in the elements of "list", where "set" has
2873 * no parameters or integer divisions.
2874 *
2875 * We collect all the constraints in those elements and then
2876 * sort the constraints such that constraints with the same linear part
2877 * are sorted together and that those with smaller constant term are
2878 * sorted first.
2879 */
uset_unshifted_simple_hull_from_basic_set_list(__isl_take isl_set * set,__isl_take isl_basic_set_list * list)2880 static __isl_give isl_basic_set *uset_unshifted_simple_hull_from_basic_set_list(
2881 __isl_take isl_set *set, __isl_take isl_basic_set_list *list)
2882 {
2883 int i, n_eq, n_ineq;
2884 isl_size n;
2885 isl_size dim;
2886 isl_ctx *ctx;
2887 isl_mat *mat = NULL;
2888 isl_int **ineq = NULL;
2889 isl_basic_set *hull;
2890
2891 n = isl_basic_set_list_n_basic_set(list);
2892 if (!set || n < 0)
2893 goto error;
2894 ctx = isl_set_get_ctx(set);
2895
2896 n_eq = 0;
2897 n_ineq = 0;
2898 for (i = 0; i < n; ++i) {
2899 isl_basic_set *bset;
2900 bset = isl_basic_set_list_get_basic_set(list, i);
2901 if (!bset)
2902 goto error;
2903 n_eq += bset->n_eq;
2904 n_ineq += 2 * bset->n_eq + bset->n_ineq;
2905 isl_basic_set_free(bset);
2906 }
2907
2908 ineq = isl_alloc_array(ctx, isl_int *, n_ineq);
2909 if (n_ineq > 0 && !ineq)
2910 goto error;
2911
2912 dim = isl_set_dim(set, isl_dim_set);
2913 if (dim < 0)
2914 goto error;
2915 mat = isl_mat_alloc(ctx, n_eq, 1 + dim);
2916 mat = collect_inequalities(mat, list, ineq);
2917 if (!mat)
2918 goto error;
2919
2920 if (isl_sort(ineq, n_ineq, sizeof(ineq[0]), &cmp_ineq, &dim) < 0)
2921 goto error;
2922
2923 hull = uset_unshifted_simple_hull_from_constraints(set, n_ineq, ineq);
2924
2925 isl_mat_free(mat);
2926 free(ineq);
2927 isl_basic_set_list_free(list);
2928 return hull;
2929 error:
2930 isl_mat_free(mat);
2931 free(ineq);
2932 isl_set_free(set);
2933 isl_basic_set_list_free(list);
2934 return NULL;
2935 }
2936
2937 /* Compute a superset of the convex hull of "map" that is described
2938 * by only constraints in the elements of "list".
2939 *
2940 * If the list is empty, then we can only describe the universe set.
2941 * If the input map is empty, then all constraints are valid, so
2942 * we return the intersection of the elements in "list".
2943 *
2944 * Otherwise, we align all divs and temporarily treat them
2945 * as regular variables, computing the unshifted simple hull in
2946 * uset_unshifted_simple_hull_from_basic_set_list.
2947 */
map_unshifted_simple_hull_from_basic_map_list(__isl_take isl_map * map,__isl_take isl_basic_map_list * list)2948 static __isl_give isl_basic_map *map_unshifted_simple_hull_from_basic_map_list(
2949 __isl_take isl_map *map, __isl_take isl_basic_map_list *list)
2950 {
2951 isl_size n;
2952 isl_basic_map *model;
2953 isl_basic_map *hull;
2954 isl_set *set;
2955 isl_basic_set_list *bset_list;
2956
2957 n = isl_basic_map_list_n_basic_map(list);
2958 if (!map || n < 0)
2959 goto error;
2960
2961 if (n == 0) {
2962 isl_space *space;
2963
2964 space = isl_map_get_space(map);
2965 isl_map_free(map);
2966 isl_basic_map_list_free(list);
2967 return isl_basic_map_universe(space);
2968 }
2969 if (isl_map_plain_is_empty(map)) {
2970 isl_map_free(map);
2971 return isl_basic_map_list_intersect(list);
2972 }
2973
2974 map = isl_map_align_divs_to_basic_map_list(map, list);
2975 if (!map)
2976 goto error;
2977 list = isl_basic_map_list_align_divs_to_basic_map(list, map->p[0]);
2978
2979 model = isl_basic_map_list_get_basic_map(list, 0);
2980
2981 set = isl_map_underlying_set(map);
2982 bset_list = isl_basic_map_list_underlying_set(list);
2983
2984 hull = uset_unshifted_simple_hull_from_basic_set_list(set, bset_list);
2985 hull = isl_basic_map_overlying_set(hull, model);
2986
2987 return hull;
2988 error:
2989 isl_map_free(map);
2990 isl_basic_map_list_free(list);
2991 return NULL;
2992 }
2993
2994 /* Return a sequence of the basic maps that make up the maps in "list".
2995 */
collect_basic_maps(__isl_take isl_map_list * list)2996 static __isl_give isl_basic_map_list *collect_basic_maps(
2997 __isl_take isl_map_list *list)
2998 {
2999 int i;
3000 isl_size n;
3001 isl_ctx *ctx;
3002 isl_basic_map_list *bmap_list;
3003
3004 if (!list)
3005 return NULL;
3006 n = isl_map_list_n_map(list);
3007 ctx = isl_map_list_get_ctx(list);
3008 bmap_list = isl_basic_map_list_alloc(ctx, 0);
3009 if (n < 0)
3010 bmap_list = isl_basic_map_list_free(bmap_list);
3011
3012 for (i = 0; i < n; ++i) {
3013 isl_map *map;
3014 isl_basic_map_list *list_i;
3015
3016 map = isl_map_list_get_map(list, i);
3017 map = isl_map_compute_divs(map);
3018 list_i = isl_map_get_basic_map_list(map);
3019 isl_map_free(map);
3020 bmap_list = isl_basic_map_list_concat(bmap_list, list_i);
3021 }
3022
3023 isl_map_list_free(list);
3024 return bmap_list;
3025 }
3026
3027 /* Compute a superset of the convex hull of "map" that is described
3028 * by only constraints in the elements of "list".
3029 *
3030 * If "map" is the universe, then the convex hull (and therefore
3031 * any superset of the convexhull) is the universe as well.
3032 *
3033 * Otherwise, we collect all the basic maps in the map list and
3034 * continue with map_unshifted_simple_hull_from_basic_map_list.
3035 */
isl_map_unshifted_simple_hull_from_map_list(__isl_take isl_map * map,__isl_take isl_map_list * list)3036 __isl_give isl_basic_map *isl_map_unshifted_simple_hull_from_map_list(
3037 __isl_take isl_map *map, __isl_take isl_map_list *list)
3038 {
3039 isl_basic_map_list *bmap_list;
3040 int is_universe;
3041
3042 is_universe = isl_map_plain_is_universe(map);
3043 if (is_universe < 0)
3044 map = isl_map_free(map);
3045 if (is_universe < 0 || is_universe) {
3046 isl_map_list_free(list);
3047 return isl_map_unshifted_simple_hull(map);
3048 }
3049
3050 bmap_list = collect_basic_maps(list);
3051 return map_unshifted_simple_hull_from_basic_map_list(map, bmap_list);
3052 }
3053
3054 /* Compute a superset of the convex hull of "set" that is described
3055 * by only constraints in the elements of "list".
3056 */
isl_set_unshifted_simple_hull_from_set_list(__isl_take isl_set * set,__isl_take isl_set_list * list)3057 __isl_give isl_basic_set *isl_set_unshifted_simple_hull_from_set_list(
3058 __isl_take isl_set *set, __isl_take isl_set_list *list)
3059 {
3060 return isl_map_unshifted_simple_hull_from_map_list(set, list);
3061 }
3062
3063 /* Given a set "set", return parametric bounds on the dimension "dim".
3064 */
set_bounds(__isl_keep isl_set * set,int dim)3065 static __isl_give isl_basic_set *set_bounds(__isl_keep isl_set *set, int dim)
3066 {
3067 isl_size set_dim = isl_set_dim(set, isl_dim_set);
3068 if (set_dim < 0)
3069 return NULL;
3070 set = isl_set_copy(set);
3071 set = isl_set_eliminate_dims(set, dim + 1, set_dim - (dim + 1));
3072 set = isl_set_eliminate_dims(set, 0, dim);
3073 return isl_set_convex_hull(set);
3074 }
3075
3076 /* Computes a "simple hull" and then check if each dimension in the
3077 * resulting hull is bounded by a symbolic constant. If not, the
3078 * hull is intersected with the corresponding bounds on the whole set.
3079 */
isl_set_bounded_simple_hull(__isl_take isl_set * set)3080 __isl_give isl_basic_set *isl_set_bounded_simple_hull(__isl_take isl_set *set)
3081 {
3082 int i, j;
3083 struct isl_basic_set *hull;
3084 isl_size nparam, dim, total;
3085 unsigned left;
3086 int removed_divs = 0;
3087
3088 hull = isl_set_simple_hull(isl_set_copy(set));
3089 nparam = isl_basic_set_dim(hull, isl_dim_param);
3090 dim = isl_basic_set_dim(hull, isl_dim_set);
3091 total = isl_basic_set_dim(hull, isl_dim_all);
3092 if (nparam < 0 || dim < 0 || total < 0)
3093 goto error;
3094
3095 for (i = 0; i < dim; ++i) {
3096 int lower = 0, upper = 0;
3097 struct isl_basic_set *bounds;
3098
3099 left = total - nparam - i - 1;
3100 for (j = 0; j < hull->n_eq; ++j) {
3101 if (isl_int_is_zero(hull->eq[j][1 + nparam + i]))
3102 continue;
3103 if (isl_seq_first_non_zero(hull->eq[j]+1+nparam+i+1,
3104 left) == -1)
3105 break;
3106 }
3107 if (j < hull->n_eq)
3108 continue;
3109
3110 for (j = 0; j < hull->n_ineq; ++j) {
3111 if (isl_int_is_zero(hull->ineq[j][1 + nparam + i]))
3112 continue;
3113 if (isl_seq_first_non_zero(hull->ineq[j]+1+nparam+i+1,
3114 left) != -1 ||
3115 isl_seq_first_non_zero(hull->ineq[j]+1+nparam,
3116 i) != -1)
3117 continue;
3118 if (isl_int_is_pos(hull->ineq[j][1 + nparam + i]))
3119 lower = 1;
3120 else
3121 upper = 1;
3122 if (lower && upper)
3123 break;
3124 }
3125
3126 if (lower && upper)
3127 continue;
3128
3129 if (!removed_divs) {
3130 set = isl_set_remove_divs(set);
3131 if (!set)
3132 goto error;
3133 removed_divs = 1;
3134 }
3135 bounds = set_bounds(set, i);
3136 hull = isl_basic_set_intersect(hull, bounds);
3137 if (!hull)
3138 goto error;
3139 }
3140
3141 isl_set_free(set);
3142 return hull;
3143 error:
3144 isl_set_free(set);
3145 isl_basic_set_free(hull);
3146 return NULL;
3147 }
3148