X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=isl_map.c;h=290ee4e07bea114919ac819f6c2593bda2c5c526;hb=c62eb37b1c7e699f01b30bb93ed605a8492f2b0b;hp=bd7cbae757550f6b9027dfdb876bf267551e3e84;hpb=0929e77a8bb341dc92f4d7a61869fc93a291f2fa;p=platform%2Fupstream%2Fisl.git diff --git a/isl_map.c b/isl_map.c index bd7cbae..290ee4e 100644 --- a/isl_map.c +++ b/isl_map.c @@ -1,6 +1,7 @@ /* * Copyright 2008-2009 Katholieke Universiteit Leuven * Copyright 2010 INRIA Saclay + * Copyright 2012 Ecole Normale Superieure * * Use of this software is governed by the GNU LGPLv2.1 license * @@ -8,6 +9,7 @@ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite, * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France */ #include @@ -30,6 +32,7 @@ #include #include #include +#include static unsigned n(__isl_keep isl_space *dim, enum isl_dim_type type) { @@ -121,6 +124,8 @@ unsigned isl_basic_set_n_param(__isl_keep isl_basic_set *bset) unsigned isl_basic_set_total_dim(const struct isl_basic_set *bset) { + if (!bset) + return 0; return isl_space_dim(bset->dim, isl_dim_all) + bset->n_div; } @@ -254,25 +259,42 @@ __isl_give isl_space *isl_basic_set_get_space(__isl_keep isl_basic_set *bset) return isl_space_copy(bset->dim); } -__isl_give isl_local_space *isl_basic_map_get_local_space( - __isl_keep isl_basic_map *bmap) +/* Extract the divs in "bmap" as a matrix. + */ +__isl_give isl_mat *isl_basic_map_get_divs(__isl_keep isl_basic_map *bmap) { int i; - isl_local_space *ls; + isl_ctx *ctx; + isl_mat *div; unsigned total; + unsigned cols; if (!bmap) return NULL; - total = isl_basic_map_total_dim(bmap); - ls = isl_local_space_alloc(isl_space_copy(bmap->dim), bmap->n_div); - if (!ls) + ctx = isl_basic_map_get_ctx(bmap); + total = isl_space_dim(bmap->dim, isl_dim_all); + cols = 1 + 1 + total + bmap->n_div; + div = isl_mat_alloc(ctx, bmap->n_div, cols); + if (!div) return NULL; for (i = 0; i < bmap->n_div; ++i) - isl_seq_cpy(ls->div->row[i], bmap->div[i], 2 + total); + isl_seq_cpy(div->row[i], bmap->div[i], cols); + + return div; +} + +__isl_give isl_local_space *isl_basic_map_get_local_space( + __isl_keep isl_basic_map *bmap) +{ + isl_mat *div; + + if (!bmap) + return NULL; - return ls; + div = isl_basic_map_get_divs(bmap); + return isl_local_space_alloc_div(isl_space_copy(bmap->dim), div); } __isl_give isl_local_space *isl_basic_set_get_local_space( @@ -454,6 +476,14 @@ __isl_give isl_id *isl_set_get_tuple_id(__isl_keep isl_set *set) return isl_map_get_tuple_id(set, isl_dim_set); } +/* Does the set tuple have a name? + */ +int isl_set_has_tuple_name(__isl_keep isl_set *set) +{ + return set ? isl_space_has_tuple_name(set->dim, isl_dim_set) : -1; +} + + const char *isl_basic_set_get_tuple_name(__isl_keep isl_basic_set *bset) { return bset ? isl_space_get_tuple_name(bset->dim, isl_dim_set) : NULL; @@ -476,6 +506,14 @@ const char *isl_basic_set_get_dim_name(__isl_keep isl_basic_set *bset, return bset ? isl_space_get_dim_name(bset->dim, type, pos) : NULL; } +/* Does the given dimension have a name? + */ +int isl_map_has_dim_name(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos) +{ + return map ? isl_space_has_dim_name(map->dim, type, pos) : -1; +} + const char *isl_map_get_dim_name(__isl_keep isl_map *map, enum isl_dim_type type, unsigned pos) { @@ -488,16 +526,25 @@ const char *isl_set_get_dim_name(__isl_keep isl_set *set, return set ? isl_space_get_dim_name(set->dim, type, pos) : NULL; } +/* Does the given dimension have a name? + */ +int isl_set_has_dim_name(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos) +{ + return set ? isl_space_has_dim_name(set->dim, type, pos) : -1; +} + __isl_give isl_basic_map *isl_basic_map_set_dim_name( __isl_take isl_basic_map *bmap, enum isl_dim_type type, unsigned pos, const char *s) { + bmap = isl_basic_map_cow(bmap); if (!bmap) return NULL; bmap->dim = isl_space_set_dim_name(bmap->dim, type, pos, s); if (!bmap->dim) goto error; - return bmap; + return isl_basic_map_finalize(bmap); error: isl_basic_map_free(bmap); return NULL; @@ -508,6 +555,7 @@ __isl_give isl_map *isl_map_set_dim_name(__isl_take isl_map *map, { int i; + map = isl_map_cow(map); if (!map) return NULL; @@ -541,6 +589,18 @@ __isl_give isl_set *isl_set_set_dim_name(__isl_take isl_set *set, return (isl_set *)isl_map_set_dim_name((isl_map *)set, type, pos, s); } +int isl_basic_map_has_dim_id(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos) +{ + return bmap ? isl_space_has_dim_id(bmap->dim, type, pos) : -1; +} + +__isl_give isl_id *isl_basic_set_get_dim_id(__isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned pos) +{ + return bset ? isl_space_get_dim_id(bset->dim, type, pos) : NULL; +} + int isl_map_has_dim_id(__isl_keep isl_map *map, enum isl_dim_type type, unsigned pos) { @@ -597,6 +657,20 @@ int isl_set_find_dim_by_id(__isl_keep isl_set *set, enum isl_dim_type type, return isl_map_find_dim_by_id(set, type, id); } +int isl_map_find_dim_by_name(__isl_keep isl_map *map, enum isl_dim_type type, + const char *name) +{ + if (!map) + return -1; + return isl_space_find_dim_by_name(map->dim, type, name); +} + +int isl_set_find_dim_by_name(__isl_keep isl_set *set, enum isl_dim_type type, + const char *name) +{ + return isl_map_find_dim_by_name(set, type, name); +} + int isl_basic_map_is_rational(__isl_keep isl_basic_map *bmap) { if (!bmap) @@ -609,6 +683,35 @@ int isl_basic_set_is_rational(__isl_keep isl_basic_set *bset) return isl_basic_map_is_rational(bset); } +/* Is this basic set a parameter domain? + */ +int isl_basic_set_is_params(__isl_keep isl_basic_set *bset) +{ + if (!bset) + return -1; + return isl_space_is_params(bset->dim); +} + +/* Is this set a parameter domain? + */ +int isl_set_is_params(__isl_keep isl_set *set) +{ + if (!set) + return -1; + return isl_space_is_params(set->dim); +} + +/* Is this map actually a parameter domain? + * Users should never call this function. Outside of isl, + * a map can never be a parameter domain. + */ +int isl_map_is_params(__isl_keep isl_map *map) +{ + if (!map) + return -1; + return isl_space_is_params(map->dim); +} + static struct isl_basic_map *basic_map_init(struct isl_ctx *ctx, struct isl_basic_map *bmap, unsigned extra, unsigned n_eq, unsigned n_ineq) @@ -866,7 +969,7 @@ error: return NULL; } -static int align_params_map_map_and_test(__isl_keep isl_map *map1, +int isl_map_align_params_map_map_and_test(__isl_keep isl_map *map1, __isl_keep isl_map *map2, int (*fn)(__isl_keep isl_map *map1, __isl_keep isl_map *map2)) { @@ -1501,8 +1604,8 @@ void isl_basic_map_swap_div(struct isl_basic_map *bmap, int a, int b) } /* Eliminate the specified n dimensions starting at first from the - * constraints using Fourier-Motzkin. The dimensions themselves - * are not removed. + * constraints, without removing the dimensions from the space. + * If the set is rational, the dimensions are eliminated using Fourier-Motzkin. */ __isl_give isl_map *isl_map_eliminate(__isl_take isl_map *map, enum isl_dim_type type, unsigned first, unsigned n) @@ -1514,14 +1617,16 @@ __isl_give isl_map *isl_map_eliminate(__isl_take isl_map *map, if (n == 0) return map; + if (first + n > isl_map_dim(map, type) || first + n < first) + isl_die(map->ctx, isl_error_invalid, + "index out of bounds", goto error); + map = isl_map_cow(map); if (!map) return NULL; - isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error); - first += pos(map->dim, type) - 1; - + for (i = 0; i < map->n; ++i) { - map->p[i] = isl_basic_map_eliminate_vars(map->p[i], first, n); + map->p[i] = isl_basic_map_eliminate(map->p[i], type, first, n); if (!map->p[i]) goto error; } @@ -1532,8 +1637,8 @@ error: } /* Eliminate the specified n dimensions starting at first from the - * constraints using Fourier-Motzkin. The dimensions themselves - * are not removed. + * constraints, without removing the dimensions from the space. + * If the set is rational, the dimensions are eliminated using Fourier-Motzkin. */ __isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set, enum isl_dim_type type, unsigned first, unsigned n) @@ -1542,8 +1647,8 @@ __isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set, } /* Eliminate the specified n dimensions starting at first from the - * constraints using Fourier-Motzkin. The dimensions themselves - * are not removed. + * constraints, without removing the dimensions from the space. + * If the set is rational, the dimensions are eliminated using Fourier-Motzkin. */ __isl_give isl_set *isl_set_eliminate_dims(__isl_take isl_set *set, unsigned first, unsigned n) @@ -1646,6 +1751,196 @@ static int div_involves_vars(__isl_keep isl_basic_map *bmap, int div, return 0; } +/* Try and add a lower and/or upper bound on "div" to "bmap" + * based on inequality "i". + * "total" is the total number of variables (excluding the divs). + * "v" is a temporary object that can be used during the calculations. + * If "lb" is set, then a lower bound should be constructed. + * If "ub" is set, then an upper bound should be constructed. + * + * The calling function has already checked that the inequality does not + * reference "div", but we still need to check that the inequality is + * of the right form. We'll consider the case where we want to construct + * a lower bound. The construction of upper bounds is similar. + * + * Let "div" be of the form + * + * q = floor((a + f(x))/d) + * + * We essentially check if constraint "i" is of the form + * + * b + f(x) >= 0 + * + * so that we can use it to derive a lower bound on "div". + * However, we allow a slightly more general form + * + * b + g(x) >= 0 + * + * with the condition that the coefficients of g(x) - f(x) are all + * divisible by d. + * Rewriting this constraint as + * + * 0 >= -b - g(x) + * + * adding a + f(x) to both sides and dividing by d, we obtain + * + * (a + f(x))/d >= (a-b)/d + (f(x)-g(x))/d + * + * Taking the floor on both sides, we obtain + * + * q >= floor((a-b)/d) + (f(x)-g(x))/d + * + * or + * + * (g(x)-f(x))/d + ceil((b-a)/d) + q >= 0 + * + * In the case of an upper bound, we construct the constraint + * + * (g(x)+f(x))/d + floor((b+a)/d) - q >= 0 + * + */ +static __isl_give isl_basic_map *insert_bounds_on_div_from_ineq( + __isl_take isl_basic_map *bmap, int div, int i, + unsigned total, isl_int v, int lb, int ub) +{ + int j; + + for (j = 0; (lb || ub) && j < total + bmap->n_div; ++j) { + if (lb) { + isl_int_sub(v, bmap->ineq[i][1 + j], + bmap->div[div][1 + 1 + j]); + lb = isl_int_is_divisible_by(v, bmap->div[div][0]); + } + if (ub) { + isl_int_add(v, bmap->ineq[i][1 + j], + bmap->div[div][1 + 1 + j]); + ub = isl_int_is_divisible_by(v, bmap->div[div][0]); + } + } + if (!lb && !ub) + return bmap; + + bmap = isl_basic_map_extend_constraints(bmap, 0, lb + ub); + if (lb) { + int k = isl_basic_map_alloc_inequality(bmap); + if (k < 0) + goto error; + for (j = 0; j < 1 + total + bmap->n_div; ++j) { + isl_int_sub(bmap->ineq[k][j], bmap->ineq[i][j], + bmap->div[div][1 + j]); + isl_int_cdiv_q(bmap->ineq[k][j], + bmap->ineq[k][j], bmap->div[div][0]); + } + isl_int_set_si(bmap->ineq[k][1 + total + div], 1); + } + if (ub) { + int k = isl_basic_map_alloc_inequality(bmap); + if (k < 0) + goto error; + for (j = 0; j < 1 + total + bmap->n_div; ++j) { + isl_int_add(bmap->ineq[k][j], bmap->ineq[i][j], + bmap->div[div][1 + j]); + isl_int_fdiv_q(bmap->ineq[k][j], + bmap->ineq[k][j], bmap->div[div][0]); + } + isl_int_set_si(bmap->ineq[k][1 + total + div], -1); + } + + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* This function is called right before "div" is eliminated from "bmap" + * using Fourier-Motzkin. + * Look through the constraints of "bmap" for constraints on the argument + * of the integer division and use them to construct constraints on the + * integer division itself. These constraints can then be combined + * during the Fourier-Motzkin elimination. + * Note that it is only useful to introduce lower bounds on "div" + * if "bmap" already contains upper bounds on "div" as the newly + * introduce lower bounds can then be combined with the pre-existing + * upper bounds. Similarly for upper bounds. + * We therefore first check if "bmap" contains any lower and/or upper bounds + * on "div". + * + * It is interesting to note that the introduction of these constraints + * can indeed lead to more accurate results, even when compared to + * deriving constraints on the argument of "div" from constraints on "div". + * Consider, for example, the set + * + * { [i,j,k] : 3 + i + 2j >= 0 and 2 * [(i+2j)/4] <= k } + * + * The second constraint can be rewritten as + * + * 2 * [(-i-2j+3)/4] + k >= 0 + * + * from which we can derive + * + * -i - 2j + 3 >= -2k + * + * or + * + * i + 2j <= 3 + 2k + * + * Combined with the first constraint, we obtain + * + * -3 <= 3 + 2k or k >= -3 + * + * If, on the other hand we derive a constraint on [(i+2j)/4] from + * the first constraint, we obtain + * + * [(i + 2j)/4] >= [-3/4] = -1 + * + * Combining this constraint with the second constraint, we obtain + * + * k >= -2 + */ +static __isl_give isl_basic_map *insert_bounds_on_div( + __isl_take isl_basic_map *bmap, int div) +{ + int i; + int check_lb, check_ub; + isl_int v; + unsigned total; + + if (!bmap) + return NULL; + + if (isl_int_is_zero(bmap->div[div][0])) + return bmap; + + total = isl_space_dim(bmap->dim, isl_dim_all); + + check_lb = 0; + check_ub = 0; + for (i = 0; (!check_lb || !check_ub) && i < bmap->n_ineq; ++i) { + int s = isl_int_sgn(bmap->ineq[i][1 + total + div]); + if (s > 0) + check_ub = 1; + if (s < 0) + check_lb = 1; + } + + if (!check_lb && !check_ub) + return bmap; + + isl_int_init(v); + + for (i = 0; bmap && i < bmap->n_ineq; ++i) { + if (!isl_int_is_zero(bmap->ineq[i][1 + total + div])) + continue; + + bmap = insert_bounds_on_div_from_ineq(bmap, div, i, total, v, + check_lb, check_ub); + } + + isl_int_clear(v); + + return bmap; +} + /* Remove all divs (recursively) involving any of the given dimensions * in their definitions. */ @@ -1664,6 +1959,7 @@ __isl_give isl_basic_map *isl_basic_map_remove_divs_involving_dims( for (i = bmap->n_div - 1; i >= 0; --i) { if (!div_involves_vars(bmap, i, first, n)) continue; + bmap = insert_bounds_on_div(bmap, i); bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, i, 1); if (!bmap) return NULL; @@ -1676,6 +1972,13 @@ error: return NULL; } +__isl_give isl_basic_set *isl_basic_set_remove_divs_involving_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return isl_basic_map_remove_divs_involving_dims(bset, type, first, n); +} + __isl_give isl_map *isl_map_remove_divs_involving_dims(__isl_take isl_map *map, enum isl_dim_type type, unsigned first, unsigned n) { @@ -1709,6 +2012,12 @@ __isl_give isl_set *isl_set_remove_divs_involving_dims(__isl_take isl_set *set, type, first, n); } +/* Does the desciption of "bmap" depend on the specified dimensions? + * We also check whether the dimensions appear in any of the div definitions. + * In principle there is no need for this check. If the dimensions appear + * in a div definition, they also appear in the defining constraints of that + * div. + */ int isl_basic_map_involves_dims(__isl_keep isl_basic_map *bmap, enum isl_dim_type type, unsigned first, unsigned n) { @@ -1728,6 +2037,12 @@ int isl_basic_map_involves_dims(__isl_keep isl_basic_map *bmap, for (i = 0; i < bmap->n_ineq; ++i) if (isl_seq_first_non_zero(bmap->ineq[i] + first, n) >= 0) return 1; + for (i = 0; i < bmap->n_div; ++i) { + if (isl_int_is_zero(bmap->div[i][0])) + continue; + if (isl_seq_first_non_zero(bmap->div[i] + 1 + first, n) >= 0) + return 1; + } return 0; } @@ -1747,11 +2062,11 @@ int isl_map_involves_dims(__isl_keep isl_map *map, for (i = 0; i < map->n; ++i) { int involves = isl_basic_map_involves_dims(map->p[i], type, first, n); - if (involves < 0 || !involves) + if (involves < 0 || involves) return involves; } - return 1; + return 0; } int isl_basic_set_involves_dims(__isl_keep isl_basic_set *bset, @@ -1801,6 +2116,9 @@ __isl_give isl_basic_map *isl_basic_map_remove_unknown_divs( if (!div_is_unknown(bmap, i)) continue; bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, i, 1); + if (!bmap) + return NULL; + i = bmap->n_div; } return bmap; @@ -2160,21 +2478,23 @@ __isl_give isl_set *isl_set_add_basic_set(__isl_take isl_set *set, (struct isl_basic_map *)bset); } -void isl_set_free(struct isl_set *set) +void *isl_set_free(__isl_take isl_set *set) { int i; if (!set) - return; + return NULL; if (--set->ref > 0) - return; + return NULL; isl_ctx_deref(set->ctx); for (i = 0; i < set->n; ++i) isl_basic_set_free(set->p[i]); isl_space_free(set->dim); free(set); + + return NULL; } void isl_set_print_internal(struct isl_set *set, FILE *out, int indent) @@ -2386,6 +2706,12 @@ struct isl_basic_set *isl_basic_set_intersect( (struct isl_basic_map *)bset2); } +__isl_give isl_basic_set *isl_basic_set_intersect_params( + __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2) +{ + return isl_basic_set_intersect(bset1, bset2); +} + /* Special case of isl_map_intersect, where both map1 and map2 * are convex, without any divs and such that either map1 or map2 * contains a single constraint. This constraint is then simply @@ -2438,7 +2764,10 @@ error: return NULL; } -static __isl_give isl_map *map_intersect(__isl_take isl_map *map1, +/* map2 may be either a parameter domain or a map living in the same + * space as map1. + */ +static __isl_give isl_map *map_intersect_internal(__isl_take isl_map *map1, __isl_take isl_map *map2) { unsigned flags = 0; @@ -2465,11 +2794,6 @@ static __isl_give isl_map *map_intersect(__isl_take isl_map *map1, (map1->p[0]->n_eq + map1->p[0]->n_ineq == 1 || map2->p[0]->n_eq + map2->p[0]->n_ineq == 1)) return map_intersect_add_constraint(map1, map2); - if (isl_space_dim(map1->dim, isl_dim_all) == - isl_space_dim(map1->dim, isl_dim_param) && - isl_space_dim(map2->dim, isl_dim_all) != - isl_space_dim(map2->dim, isl_dim_param)) - return isl_map_intersect(map2, map1); if (isl_space_dim(map2->dim, isl_dim_all) != isl_space_dim(map2->dim, isl_dim_param)) @@ -2506,6 +2830,21 @@ error: return NULL; } +static __isl_give isl_map *map_intersect(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + if (!map1 || !map2) + goto error; + if (!isl_space_is_equal(map1->dim, map2->dim)) + isl_die(isl_map_get_ctx(map1), isl_error_invalid, + "spaces don't match", goto error); + return map_intersect_internal(map1, map2); +error: + isl_map_free(map1); + isl_map_free(map2); + return NULL; +} + __isl_give isl_map *isl_map_intersect(__isl_take isl_map *map1, __isl_take isl_map *map2) { @@ -2519,13 +2858,13 @@ struct isl_set *isl_set_intersect(struct isl_set *set1, struct isl_set *set2) (struct isl_map *)set2); } -/* The current implementation of isl_map_intersect accepts intersections - * with parameter domains, so we can just call that for now. +/* map_intersect_internal accepts intersections + * with parameter domains, so we can just call that function. */ static __isl_give isl_map *map_intersect_params(__isl_take isl_map *map, __isl_take isl_set *params) { - return isl_map_intersect(map, params); + return map_intersect_internal(map, params); } __isl_give isl_map *isl_map_intersect_params(__isl_take isl_map *map1, @@ -2572,8 +2911,9 @@ static __isl_give isl_basic_map *basic_map_space_reset( return bmap; } -__isl_give isl_basic_map *isl_basic_map_insert(__isl_take isl_basic_map *bmap, - enum isl_dim_type type, unsigned pos, unsigned n) +__isl_give isl_basic_map *isl_basic_map_insert_dims( + __isl_take isl_basic_map *bmap, enum isl_dim_type type, + unsigned pos, unsigned n) { isl_space *res_dim; struct isl_basic_map *res; @@ -2610,16 +2950,27 @@ __isl_give isl_basic_map *isl_basic_map_insert(__isl_take isl_basic_map *bmap, bmap->n_div, bmap->n_eq, bmap->n_ineq); if (isl_basic_map_is_rational(bmap)) res = isl_basic_map_set_rational(res); + if (isl_basic_map_plain_is_empty(bmap)) { + isl_basic_map_free(bmap); + return isl_basic_map_set_to_empty(res); + } res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map); return isl_basic_map_finalize(res); } +__isl_give isl_basic_set *isl_basic_set_insert_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, unsigned n) +{ + return isl_basic_map_insert_dims(bset, type, pos, n); +} + __isl_give isl_basic_map *isl_basic_map_add(__isl_take isl_basic_map *bmap, enum isl_dim_type type, unsigned n) { if (!bmap) return NULL; - return isl_basic_map_insert(bmap, type, + return isl_basic_map_insert_dims(bmap, type, isl_basic_map_dim(bmap, type), n); } @@ -2640,7 +2991,7 @@ static __isl_give isl_map *map_space_reset(__isl_take isl_map *map, { isl_space *space; - if (!isl_space_is_named_or_nested(map->dim, type)) + if (!map || !isl_space_is_named_or_nested(map->dim, type)) return map; space = isl_map_get_space(map); @@ -2666,7 +3017,7 @@ __isl_give isl_map *isl_map_insert_dims(__isl_take isl_map *map, goto error; for (i = 0; i < map->n; ++i) { - map->p[i] = isl_basic_map_insert(map->p[i], type, pos, n); + map->p[i] = isl_basic_map_insert_dims(map->p[i], type, pos, n); if (!map->p[i]) goto error; } @@ -2914,7 +3265,7 @@ __isl_give isl_basic_map *isl_basic_map_project_out( isl_int *old; if (n == 0) - return bmap; + return basic_map_space_reset(bmap, type); if (!bmap) return NULL; @@ -2984,7 +3335,7 @@ __isl_give isl_map *isl_map_project_out(__isl_take isl_map *map, return NULL; if (n == 0) - return map; + return map_space_reset(map, type); isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error); @@ -4057,6 +4408,70 @@ __isl_give isl_set *isl_set_reset_space(__isl_take isl_set *set, return (struct isl_set *) isl_map_reset_space((struct isl_map *)set, dim); } +/* Compute the parameter domain of the given basic set. + */ +__isl_give isl_basic_set *isl_basic_set_params(__isl_take isl_basic_set *bset) +{ + isl_space *space; + unsigned n; + + if (isl_basic_set_is_params(bset)) + return bset; + + n = isl_basic_set_dim(bset, isl_dim_set); + bset = isl_basic_set_project_out(bset, isl_dim_set, 0, n); + space = isl_basic_set_get_space(bset); + space = isl_space_params(space); + bset = isl_basic_set_reset_space(bset, space); + return bset; +} + +/* Compute the parameter domain of the given set. + */ +__isl_give isl_set *isl_set_params(__isl_take isl_set *set) +{ + isl_space *space; + unsigned n; + + if (isl_set_is_params(set)) + return set; + + n = isl_set_dim(set, isl_dim_set); + set = isl_set_project_out(set, isl_dim_set, 0, n); + space = isl_set_get_space(set); + space = isl_space_params(space); + set = isl_set_reset_space(set, space); + return set; +} + +/* Construct a zero-dimensional set with the given parameter domain. + */ +__isl_give isl_set *isl_set_from_params(__isl_take isl_set *set) +{ + isl_space *space; + space = isl_set_get_space(set); + space = isl_space_set_from_params(space); + set = isl_set_reset_space(set, space); + return set; +} + +/* Compute the parameter domain of the given map. + */ +__isl_give isl_set *isl_map_params(__isl_take isl_map *map) +{ + isl_space *space; + unsigned n; + + n = isl_map_dim(map, isl_dim_in); + map = isl_map_project_out(map, isl_dim_in, 0, n); + n = isl_map_dim(map, isl_dim_out); + map = isl_map_project_out(map, isl_dim_out, 0, n); + space = isl_map_get_space(map); + space = isl_space_params(space); + map = isl_map_reset_space(map, space); + return map; +} + struct isl_basic_set *isl_basic_map_domain(struct isl_basic_map *bmap) { isl_space *dim; @@ -4085,13 +4500,24 @@ int isl_basic_map_may_be_set(__isl_keep isl_basic_map *bmap) return isl_space_may_be_set(bmap->dim); } -struct isl_basic_set *isl_basic_map_range(struct isl_basic_map *bmap) +/* Is this basic map actually a set? + * Users should never call this function. Outside of isl, + * the type should indicate whether something is a set or a map. + */ +int isl_basic_map_is_set(__isl_keep isl_basic_map *bmap) { if (!bmap) - return NULL; - if (isl_basic_map_may_be_set(bmap)) - return bmap; - return isl_basic_map_domain(isl_basic_map_reverse(bmap)); + return -1; + return isl_space_is_set(bmap->dim); +} + +struct isl_basic_set *isl_basic_map_range(struct isl_basic_map *bmap) +{ + if (!bmap) + return NULL; + if (isl_basic_map_is_set(bmap)) + return bmap; + return isl_basic_map_domain(isl_basic_map_reverse(bmap)); } __isl_give isl_basic_map *isl_basic_map_domain_map( @@ -4177,6 +4603,17 @@ int isl_map_may_be_set(__isl_keep isl_map *map) return isl_space_may_be_set(map->dim); } +/* Is this map actually a set? + * Users should never call this function. Outside of isl, + * the type should indicate whether something is a set or a map. + */ +int isl_map_is_set(__isl_keep isl_map *map) +{ + if (!map) + return -1; + return isl_space_is_set(map->dim); +} + struct isl_set *isl_map_range(struct isl_map *map) { int i; @@ -4184,7 +4621,7 @@ struct isl_set *isl_map_range(struct isl_map *map) if (!map) goto error; - if (isl_map_may_be_set(map)) + if (isl_map_is_set(map)) return (isl_set *)map; map = isl_map_cow(map); @@ -4298,11 +4735,19 @@ __isl_give isl_basic_map *isl_basic_map_from_domain( __isl_give isl_basic_map *isl_basic_map_from_range( __isl_take isl_basic_set *bset) { + isl_space *space; + space = isl_basic_set_get_space(bset); + space = isl_space_from_range(space); + bset = isl_basic_set_reset_space(bset, space); return (isl_basic_map *)bset; } struct isl_map *isl_map_from_range(struct isl_set *set) { + isl_space *space; + space = isl_set_get_space(set); + space = isl_space_from_range(space); + set = isl_set_reset_space(set, space); return (struct isl_map *)set; } @@ -4314,15 +4759,13 @@ __isl_give isl_map *isl_map_from_domain(__isl_take isl_set *set) __isl_give isl_basic_map *isl_basic_map_from_domain_and_range( __isl_take isl_basic_set *domain, __isl_take isl_basic_set *range) { - return isl_basic_map_apply_range(isl_basic_map_from_domain(domain), - isl_basic_map_from_range(range)); + return isl_basic_map_apply_range(isl_basic_map_reverse(domain), range); } __isl_give isl_map *isl_map_from_domain_and_range(__isl_take isl_set *domain, __isl_take isl_set *range) { - return isl_map_apply_range(isl_map_from_domain(domain), - isl_map_from_range(range)); + return isl_map_apply_range(isl_map_reverse(domain), range); } struct isl_set *isl_set_from_map(struct isl_map *map) @@ -4357,7 +4800,9 @@ __isl_give isl_map *isl_map_alloc_space(__isl_take isl_space *dim, int n, if (!dim) return NULL; - isl_assert(dim->ctx, n >= 0, return NULL); + if (n < 0) + isl_die(dim->ctx, isl_error_internal, + "negative number of basic maps", goto error); map = isl_alloc(dim->ctx, struct isl_map, sizeof(struct isl_map) + (n - 1) * sizeof(struct isl_basic_map *)); @@ -4750,6 +5195,25 @@ struct isl_basic_set *isl_basic_set_fix_dim_si(struct isl_basic_set *bset, isl_dim_set, dim, value); } +static int remove_if_empty(__isl_keep isl_map *map, int i) +{ + int empty = isl_basic_map_plain_is_empty(map->p[i]); + + if (empty < 0) + return -1; + if (!empty) + return 0; + + isl_basic_map_free(map->p[i]); + if (i != map->n - 1) { + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + map->p[i] = map->p[map->n - 1]; + } + map->n--; + + return 0; +} + struct isl_map *isl_map_fix_si(struct isl_map *map, enum isl_dim_type type, unsigned pos, int value) { @@ -4760,9 +5224,9 @@ struct isl_map *isl_map_fix_si(struct isl_map *map, return NULL; isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error); - for (i = 0; i < map->n; ++i) { + for (i = map->n - 1; i >= 0; --i) { map->p[i] = isl_basic_map_fix_si(map->p[i], type, pos, value); - if (!map->p[i]) + if (remove_if_empty(map, i) < 0) goto error; } ISL_F_CLR(map, ISL_MAP_NORMALIZED); @@ -4819,9 +5283,9 @@ struct isl_set *isl_set_fix_dim_si(struct isl_set *set, unsigned dim, int value) isl_map_fix_si((struct isl_map *)set, isl_dim_set, dim, value); } -__isl_give isl_basic_map *isl_basic_map_lower_bound_si( - __isl_take isl_basic_map *bmap, - enum isl_dim_type type, unsigned pos, int value) +static __isl_give isl_basic_map *basic_map_bound_si( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, int value, int upper) { int j; @@ -4835,8 +5299,13 @@ __isl_give isl_basic_map *isl_basic_map_lower_bound_si( if (j < 0) goto error; isl_seq_clr(bmap->ineq[j], 1 + isl_basic_map_total_dim(bmap)); - isl_int_set_si(bmap->ineq[j][pos], 1); - isl_int_set_si(bmap->ineq[j][0], -value); + if (upper) { + isl_int_set_si(bmap->ineq[j][pos], -1); + isl_int_set_si(bmap->ineq[j][0], value); + } else { + isl_int_set_si(bmap->ineq[j][pos], 1); + isl_int_set_si(bmap->ineq[j][0], -value); + } bmap = isl_basic_map_simplify(bmap); return isl_basic_map_finalize(bmap); error: @@ -4844,6 +5313,13 @@ error: return NULL; } +__isl_give isl_basic_map *isl_basic_map_lower_bound_si( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, int value) +{ + return basic_map_bound_si(bmap, type, pos, value, 0); +} + struct isl_basic_set *isl_basic_set_lower_bound_dim(struct isl_basic_set *bset, unsigned dim, isl_int value) { @@ -4864,8 +5340,8 @@ error: return NULL; } -__isl_give isl_map *isl_map_lower_bound_si(__isl_take isl_map *map, - enum isl_dim_type type, unsigned pos, int value) +static __isl_give isl_map *map_bound_si(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, int value, int upper) { int i; @@ -4875,8 +5351,8 @@ __isl_give isl_map *isl_map_lower_bound_si(__isl_take isl_map *map, isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error); for (i = 0; i < map->n; ++i) { - map->p[i] = isl_basic_map_lower_bound_si(map->p[i], - type, pos, value); + map->p[i] = basic_map_bound_si(map->p[i], + type, pos, value, upper); if (!map->p[i]) goto error; } @@ -4887,6 +5363,18 @@ error: return NULL; } +__isl_give isl_map *isl_map_lower_bound_si(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, int value) +{ + return map_bound_si(map, type, pos, value, 0); +} + +__isl_give isl_map *isl_map_upper_bound_si(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, int value) +{ + return map_bound_si(map, type, pos, value, 1); +} + __isl_give isl_set *isl_set_lower_bound_si(__isl_take isl_set *set, enum isl_dim_type type, unsigned pos, int value) { @@ -4894,6 +5382,98 @@ __isl_give isl_set *isl_set_lower_bound_si(__isl_take isl_set *set, isl_map_lower_bound_si((struct isl_map *)set, type, pos, value); } +__isl_give isl_set *isl_set_upper_bound_si(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, int value) +{ + return isl_map_upper_bound_si(set, type, pos, value); +} + +/* Bound the given variable of "bmap" from below (or above is "upper" + * is set) to "value". + */ +static __isl_give isl_basic_map *basic_map_bound( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, isl_int value, int upper) +{ + int j; + + if (!bmap) + return NULL; + if (pos >= isl_basic_map_dim(bmap, type)) + isl_die(bmap->ctx, isl_error_invalid, + "index out of bounds", goto error); + pos += isl_basic_map_offset(bmap, type); + bmap = isl_basic_map_cow(bmap); + bmap = isl_basic_map_extend_constraints(bmap, 0, 1); + j = isl_basic_map_alloc_inequality(bmap); + if (j < 0) + goto error; + isl_seq_clr(bmap->ineq[j], 1 + isl_basic_map_total_dim(bmap)); + if (upper) { + isl_int_set_si(bmap->ineq[j][pos], -1); + isl_int_set(bmap->ineq[j][0], value); + } else { + isl_int_set_si(bmap->ineq[j][pos], 1); + isl_int_neg(bmap->ineq[j][0], value); + } + bmap = isl_basic_map_simplify(bmap); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Bound the given variable of "map" from below (or above is "upper" + * is set) to "value". + */ +static __isl_give isl_map *map_bound(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, isl_int value, int upper) +{ + int i; + + map = isl_map_cow(map); + if (!map) + return NULL; + + if (pos >= isl_map_dim(map, type)) + isl_die(map->ctx, isl_error_invalid, + "index out of bounds", goto error); + for (i = map->n - 1; i >= 0; --i) { + map->p[i] = basic_map_bound(map->p[i], type, pos, value, upper); + if (remove_if_empty(map, i) < 0) + goto error; + } + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_map *isl_map_lower_bound(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, isl_int value) +{ + return map_bound(map, type, pos, value, 0); +} + +__isl_give isl_map *isl_map_upper_bound(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, isl_int value) +{ + return map_bound(map, type, pos, value, 1); +} + +__isl_give isl_set *isl_set_lower_bound(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, isl_int value) +{ + return isl_map_lower_bound(set, type, pos, value); +} + +__isl_give isl_set *isl_set_upper_bound(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, isl_int value) +{ + return isl_map_upper_bound(set, type, pos, value); +} + struct isl_set *isl_set_lower_bound_dim(struct isl_set *set, unsigned dim, isl_int value) { @@ -4988,58 +5568,143 @@ struct isl_set *isl_basic_set_partial_lexmax( dom, empty); } -/* Given a basic map "bmap", compute the lexicographically minimal - * (or maximal) image element for each domain element in dom. +__isl_give isl_pw_multi_aff *isl_basic_map_partial_lexmin_pw_multi_aff( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty) +{ + return isl_basic_map_partial_lexopt_pw_multi_aff(bmap, dom, empty, 0); +} + +__isl_give isl_pw_multi_aff *isl_basic_map_partial_lexmax_pw_multi_aff( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty) +{ + return isl_basic_map_partial_lexopt_pw_multi_aff(bmap, dom, empty, 1); +} + +__isl_give isl_pw_multi_aff *isl_basic_set_partial_lexmin_pw_multi_aff( + __isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty) +{ + return isl_basic_map_partial_lexmin_pw_multi_aff(bset, dom, empty); +} + +__isl_give isl_pw_multi_aff *isl_basic_set_partial_lexmax_pw_multi_aff( + __isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty) +{ + return isl_basic_map_partial_lexmax_pw_multi_aff(bset, dom, empty); +} + +__isl_give isl_pw_multi_aff *isl_basic_map_lexopt_pw_multi_aff( + __isl_take isl_basic_map *bmap, int max) +{ + isl_basic_set *dom = NULL; + isl_space *dom_space; + + if (!bmap) + goto error; + dom_space = isl_space_domain(isl_space_copy(bmap->dim)); + dom = isl_basic_set_universe(dom_space); + return isl_basic_map_partial_lexopt_pw_multi_aff(bmap, dom, NULL, max); +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_pw_multi_aff *isl_basic_map_lexmin_pw_multi_aff( + __isl_take isl_basic_map *bmap) +{ + return isl_basic_map_lexopt_pw_multi_aff(bmap, 0); +} + +#undef TYPE +#define TYPE isl_pw_multi_aff +#undef SUFFIX +#define SUFFIX _pw_multi_aff +#undef EMPTY +#define EMPTY isl_pw_multi_aff_empty +#undef ADD +#define ADD isl_pw_multi_aff_union_add +#include "isl_map_lexopt_templ.c" + +/* Given a map "map", compute the lexicographically minimal + * (or maximal) image element for each domain element in dom, + * in the form of an isl_pw_multi_aff. * Set *empty to those elements in dom that do not have an image element. * - * We first make sure the basic sets in dom are disjoint and then - * simply collect the results over each of the basic sets separately. - * We could probably improve the efficiency a bit by moving the union - * domain down into the parametric integer programming. + * We first compute the lexicographically minimal or maximal element + * in the first basic map. This results in a partial solution "res" + * and a subset "todo" of dom that still need to be handled. + * We then consider each of the remaining maps in "map" and successively + * update both "res" and "todo". */ -static __isl_give isl_map *basic_map_partial_lexopt( - __isl_take isl_basic_map *bmap, __isl_take isl_set *dom, - __isl_give isl_set **empty, int max) +static __isl_give isl_pw_multi_aff *isl_map_partial_lexopt_aligned_pw_multi_aff( + __isl_take isl_map *map, __isl_take isl_set *dom, + __isl_give isl_set **empty, int max) { int i; - struct isl_map *res; + isl_pw_multi_aff *res; + isl_set *todo; - dom = isl_set_make_disjoint(dom); - if (!dom) + if (!map || !dom) goto error; - if (isl_set_plain_is_empty(dom)) { - res = isl_map_empty_like_basic_map(bmap); - *empty = isl_set_empty_like(dom); - isl_set_free(dom); - isl_basic_map_free(bmap); - return res; + if (isl_map_plain_is_empty(map)) { + if (empty) + *empty = dom; + else + isl_set_free(dom); + return isl_pw_multi_aff_from_map(map); } - res = isl_basic_map_partial_lexopt(isl_basic_map_copy(bmap), - isl_basic_set_copy(dom->p[0]), empty, max); - - for (i = 1; i < dom->n; ++i) { - struct isl_map *res_i; - struct isl_set *empty_i; + res = basic_map_partial_lexopt_pw_multi_aff( + isl_basic_map_copy(map->p[0]), + isl_set_copy(dom), &todo, max); - res_i = isl_basic_map_partial_lexopt(isl_basic_map_copy(bmap), - isl_basic_set_copy(dom->p[i]), &empty_i, max); + for (i = 1; i < map->n; ++i) { + isl_pw_multi_aff *res_i; + isl_set *todo_i; - res = isl_map_union_disjoint(res, res_i); - *empty = isl_set_union_disjoint(*empty, empty_i); + res_i = basic_map_partial_lexopt_pw_multi_aff( + isl_basic_map_copy(map->p[i]), + isl_set_copy(dom), &todo_i, max); + + if (max) + res = isl_pw_multi_aff_union_lexmax(res, res_i); + else + res = isl_pw_multi_aff_union_lexmin(res, res_i); + + todo = isl_set_intersect(todo, todo_i); } isl_set_free(dom); - isl_basic_map_free(bmap); + isl_map_free(map); + + if (empty) + *empty = todo; + else + isl_set_free(todo); + return res; error: - *empty = NULL; + if (empty) + *empty = NULL; isl_set_free(dom); - isl_basic_map_free(bmap); + isl_map_free(map); return NULL; } +#undef TYPE +#define TYPE isl_map +#undef SUFFIX +#define SUFFIX +#undef EMPTY +#define EMPTY isl_map_empty +#undef ADD +#define ADD isl_map_union_disjoint +#include "isl_map_lexopt_templ.c" + /* Given a map "map", compute the lexicographically minimal * (or maximal) image element for each domain element in dom. * Set *empty to those elements in dom that do not have an image element. @@ -5048,7 +5713,7 @@ error: * in the first basic map. This results in a partial solution "res" * and a subset "todo" of dom that still need to be handled. * We then consider each of the remaining maps in "map" and successively - * improve both "res" and "todo". + * update both "res" and "todo". * * Let res^k and todo^k be the results after k steps and let i = k + 1. * Assume we are computing the lexicographical maximum. @@ -5167,35 +5832,6 @@ error: return NULL; } -/* Given a map "map", compute the lexicographically minimal - * (or maximal) image element for each domain element in dom. - * Set *empty to those elements in dom that do not have an image element. - * - * Align parameters if needed and then call isl_map_partial_lexopt_aligned. - */ -static __isl_give isl_map *isl_map_partial_lexopt( - __isl_take isl_map *map, __isl_take isl_set *dom, - __isl_give isl_set **empty, int max) -{ - if (!map || !dom) - goto error; - if (isl_space_match(map->dim, isl_dim_param, dom->dim, isl_dim_param)) - return isl_map_partial_lexopt_aligned(map, dom, empty, max); - if (!isl_space_has_named_params(map->dim) || - !isl_space_has_named_params(dom->dim)) - isl_die(map->ctx, isl_error_invalid, - "unaligned unnamed parameters", goto error); - map = isl_map_align_params(map, isl_map_get_space(dom)); - dom = isl_map_align_params(dom, isl_map_get_space(map)); - return isl_map_partial_lexopt_aligned(map, dom, empty, max); -error: - if (empty) - *empty = NULL; - isl_set_free(dom); - isl_map_free(map); - return NULL; -} - __isl_give isl_map *isl_map_partial_lexmax( __isl_take isl_map *map, __isl_take isl_set *dom, __isl_give isl_set **empty) @@ -5263,31 +5899,6 @@ __isl_give isl_set *isl_basic_set_lexmax(__isl_take isl_basic_set *bset) return (isl_set *)isl_basic_map_lexmax((isl_basic_map *)bset); } -__isl_give isl_map *isl_map_lexopt(__isl_take isl_map *map, int max) -{ - struct isl_set *dom = NULL; - isl_space *dom_dim; - - if (!map) - goto error; - dom_dim = isl_space_domain(isl_space_copy(map->dim)); - dom = isl_set_universe(dom_dim); - return isl_map_partial_lexopt(map, dom, NULL, max); -error: - isl_map_free(map); - return NULL; -} - -__isl_give isl_map *isl_map_lexmin(__isl_take isl_map *map) -{ - return isl_map_lexopt(map, 0); -} - -__isl_give isl_map *isl_map_lexmax(__isl_take isl_map *map) -{ - return isl_map_lexopt(map, 1); -} - __isl_give isl_set *isl_set_lexmin(__isl_take isl_set *set) { return (isl_set *)isl_map_lexmin((isl_map *)set); @@ -5298,35 +5909,10 @@ __isl_give isl_set *isl_set_lexmax(__isl_take isl_set *set) return (isl_set *)isl_map_lexmax((isl_map *)set); } -/* Construct a map that equates the two given dimensions in the given space. - */ -static __isl_give isl_map *equate(__isl_take isl_space *dim, - enum isl_dim_type src_type, int src_pos, - enum isl_dim_type dst_type, int dst_pos) -{ - isl_basic_map *bmap; - int k; - - bmap = isl_basic_map_alloc_space(dim, 0, 1, 0); - k = isl_basic_map_alloc_equality(bmap); - if (k < 0) - goto error; - isl_seq_clr(bmap->eq[k], 1 + isl_basic_map_total_dim(bmap)); - src_pos += isl_basic_map_offset(bmap, src_type); - dst_pos += isl_basic_map_offset(bmap, dst_type); - isl_int_set_si(bmap->eq[k][src_pos], 1); - isl_int_set_si(bmap->eq[k][dst_pos], -1); - - return isl_map_from_basic_map(bmap); -error: - isl_basic_map_free(bmap); - return NULL; -} - /* Extract the first and only affine expression from list * and then add it to *pwaff with the given dom. * This domain is known to be disjoint from other domains - * because of the way isl_basic_set_foreach_lexmax works. + * because of the way isl_basic_map_foreach_lexmax works. */ static int update_dim_opt(__isl_take isl_basic_set *dom, __isl_take isl_aff_list *list, void *user) @@ -5354,73 +5940,90 @@ error: return -1; } -/* Given a one-dimensional basic set, compute the minimum or maximum of that - * dimension as an isl_pw_aff. +/* Given a basic map with one output dimension, compute the minimum or + * maximum of that dimension as an isl_pw_aff. * - * The isl_pw_aff is constructed by having isl_basic_set_foreach_lexopt + * The isl_pw_aff is constructed by having isl_basic_map_foreach_lexopt * call update_dim_opt on each leaf of the result. */ -static __isl_give isl_pw_aff *basic_set_dim_opt(__isl_keep isl_basic_set *bset, +static __isl_give isl_pw_aff *basic_map_dim_opt(__isl_keep isl_basic_map *bmap, int max) { - isl_space *dim = isl_basic_set_get_space(bset); + isl_space *dim = isl_basic_map_get_space(bmap); isl_pw_aff *pwaff; int r; - dim = isl_space_domain(isl_space_from_range(dim)); + dim = isl_space_from_domain(isl_space_domain(dim)); + dim = isl_space_add_dims(dim, isl_dim_out, 1); pwaff = isl_pw_aff_empty(dim); - r = isl_basic_set_foreach_lexopt(bset, max, &update_dim_opt, &pwaff); + r = isl_basic_map_foreach_lexopt(bmap, max, &update_dim_opt, &pwaff); if (r < 0) return isl_pw_aff_free(pwaff); return pwaff; } -/* Compute the minimum or maximum of the given set dimension - * as a function of the parameters, but independently of - * the other set dimensions. +/* Compute the minimum or maximum of the given output dimension + * as a function of the parameters and the input dimensions, + * but independently of the other output dimensions. * - * We first project the set onto the given dimension and then compute - * the "lexicographic" maximum in each basic set, combining the results + * We first project out the other output dimension and then compute + * the "lexicographic" maximum in each basic map, combining the results * using isl_pw_aff_union_max. */ -static __isl_give isl_pw_aff *set_dim_opt(__isl_take isl_set *set, int pos, +static __isl_give isl_pw_aff *map_dim_opt(__isl_take isl_map *map, int pos, int max) { int i; - isl_map *map; isl_pw_aff *pwaff; + unsigned n_out; - map = isl_map_from_domain(set); - map = isl_map_add_dims(map, isl_dim_out, 1); - map = isl_map_intersect(map, - equate(isl_map_get_space(map), isl_dim_in, pos, - isl_dim_out, 0)); - set = isl_map_range(map); - if (!set) + n_out = isl_map_dim(map, isl_dim_out); + map = isl_map_project_out(map, isl_dim_out, pos + 1, n_out - (pos + 1)); + map = isl_map_project_out(map, isl_dim_out, 0, pos); + if (!map) return NULL; - if (set->n == 0) { - isl_space *dim = isl_set_get_space(set); + if (map->n == 0) { + isl_space *dim = isl_map_get_space(map); dim = isl_space_domain(isl_space_from_range(dim)); - isl_set_free(set); + isl_map_free(map); return isl_pw_aff_empty(dim); } - pwaff = basic_set_dim_opt(set->p[0], max); - for (i = 1; i < set->n; ++i) { + pwaff = basic_map_dim_opt(map->p[0], max); + for (i = 1; i < map->n; ++i) { isl_pw_aff *pwaff_i; - pwaff_i = basic_set_dim_opt(set->p[i], max); + pwaff_i = basic_map_dim_opt(map->p[i], max); pwaff = isl_pw_aff_union_opt(pwaff, pwaff_i, max); } - isl_set_free(set); + isl_map_free(map); return pwaff; } +/* Compute the maximum of the given output dimension as a function of the + * parameters and input dimensions, but independently of + * the other output dimensions. + */ +__isl_give isl_pw_aff *isl_map_dim_max(__isl_take isl_map *map, int pos) +{ + return map_dim_opt(map, pos, 1); +} + +/* Compute the minimum or maximum of the given set dimension + * as a function of the parameters, + * but independently of the other set dimensions. + */ +static __isl_give isl_pw_aff *set_dim_opt(__isl_take isl_set *set, int pos, + int max) +{ + return map_dim_opt(set, pos, max); +} + /* Compute the maximum of the given set dimension as a function of the * parameters, but independently of the other set dimensions. */ @@ -6066,7 +6669,7 @@ error: /* * returns range - domain */ -struct isl_set *isl_map_deltas(struct isl_map *map) +__isl_give isl_set *isl_map_deltas(__isl_take isl_map *map) { int i; isl_space *dim; @@ -6444,6 +7047,12 @@ int isl_basic_map_is_subset( return is_subset; } +int isl_basic_set_is_subset(__isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2) +{ + return isl_basic_map_is_subset(bset1, bset2); +} + int isl_basic_map_is_equal( struct isl_basic_map *bmap1, struct isl_basic_map *bmap2) { @@ -6538,7 +7147,7 @@ static int map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2) int isl_map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2) { - return align_params_map_map_and_test(map1, map2, &map_is_equal); + return isl_map_align_params_map_map_and_test(map1, map2, &map_is_equal); } int isl_basic_map_is_strict_subset( @@ -6697,7 +7306,7 @@ struct isl_map *isl_basic_map_union( { struct isl_map *map; if (!bmap1 || !bmap2) - return NULL; + goto error; isl_assert(bmap1->ctx, isl_space_is_equal(bmap1->dim, bmap2->dim), goto error); @@ -6947,16 +7556,8 @@ struct isl_map *isl_map_remove_empty_parts(struct isl_map *map) if (!map) return NULL; - for (i = map->n-1; i >= 0; --i) { - if (!ISL_F_ISSET(map->p[i], ISL_BASIC_MAP_EMPTY)) - continue; - isl_basic_map_free(map->p[i]); - if (i != map->n-1) { - ISL_F_CLR(map, ISL_MAP_NORMALIZED); - map->p[i] = map->p[map->n-1]; - } - map->n--; - } + for (i = map->n - 1; i >= 0; --i) + remove_if_empty(map, i); return map; } @@ -7269,6 +7870,12 @@ int isl_map_plain_is_fixed(__isl_keep isl_map *map, map_offset(map, type) - 1 + pos, val); } +int isl_set_plain_is_fixed(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos, isl_int *val) +{ + return isl_map_plain_is_fixed(set, type, pos, val); +} + int isl_map_fast_is_fixed(__isl_keep isl_map *map, enum isl_dim_type type, unsigned pos, isl_int *val) { @@ -7511,6 +8118,31 @@ int isl_basic_map_plain_cmp(const __isl_keep isl_basic_map *bmap1, return 0; } +int isl_basic_set_plain_cmp(const __isl_keep isl_basic_set *bset1, + const __isl_keep isl_basic_set *bset2) +{ + return isl_basic_map_plain_cmp(bset1, bset2); +} + +int isl_set_plain_cmp(const __isl_keep isl_set *set1, + const __isl_keep isl_set *set2) +{ + int i, cmp; + + if (set1 == set2) + return 0; + if (set1->n != set2->n) + return set1->n - set2->n; + + for (i = 0; i < set1->n; ++i) { + cmp = isl_basic_set_plain_cmp(set1->p[i], set2->p[i]); + if (cmp) + return cmp; + } + + return 0; +} + int isl_basic_map_plain_is_equal(__isl_keep isl_basic_map *bmap1, __isl_keep isl_basic_map *bmap2) { @@ -7826,6 +8458,11 @@ __isl_give isl_basic_map *isl_basic_map_range_product( if (!bmap1 || !bmap2) goto error; + if (!isl_space_match(bmap1->dim, isl_dim_param, + bmap2->dim, isl_dim_param)) + isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid, + "parameters don't match", goto error); + dim_result = isl_space_range_product(isl_space_copy(bmap1->dim), isl_space_copy(bmap2->dim)); @@ -8449,7 +9086,7 @@ int isl_basic_set_vars_get_sign(__isl_keep isl_basic_set *bset, return -1; bound = isl_vec_alloc(bset->ctx, 1 + isl_basic_set_total_dim(bset)); - tab = isl_tab_from_basic_set(bset); + tab = isl_tab_from_basic_set(bset, 0); if (!bound || !tab) goto error; @@ -8539,6 +9176,39 @@ int isl_basic_map_plain_is_single_valued(__isl_keep isl_basic_map *bmap) return 1; } +/* Check if the given basic map is single-valued. + * We simply compute + * + * M \circ M^-1 + * + * and check if the result is a subset of the identity mapping. + */ +int isl_basic_map_is_single_valued(__isl_keep isl_basic_map *bmap) +{ + isl_space *space; + isl_basic_map *test; + isl_basic_map *id; + int sv; + + sv = isl_basic_map_plain_is_single_valued(bmap); + if (sv < 0 || sv) + return sv; + + test = isl_basic_map_reverse(isl_basic_map_copy(bmap)); + test = isl_basic_map_apply_range(test, isl_basic_map_copy(bmap)); + + space = isl_basic_map_get_space(bmap); + space = isl_space_map_from_set(isl_space_range(space)); + id = isl_basic_map_identity(space); + + sv = isl_basic_map_is_subset(test, id); + + isl_basic_map_free(test); + isl_basic_map_free(id); + + return sv; +} + /* Check if the given map is obviously single-valued. */ int isl_map_plain_is_single_valued(__isl_keep isl_map *map) @@ -9052,14 +9722,21 @@ __isl_give isl_basic_map *isl_basic_map_realign(__isl_take isl_basic_map *bmap, __isl_take isl_space *dim, __isl_take struct isl_dim_map *dim_map) { isl_basic_map *res; + unsigned flags; bmap = isl_basic_map_cow(bmap); if (!bmap || !dim || !dim_map) goto error; + flags = bmap->flags; + ISL_FL_CLR(flags, ISL_BASIC_MAP_FINAL); + ISL_FL_CLR(flags, ISL_BASIC_MAP_NORMALIZED); + ISL_FL_CLR(flags, ISL_BASIC_MAP_NORMALIZED_DIVS); res = isl_basic_map_alloc_space(dim, bmap->n_div, bmap->n_eq, bmap->n_ineq); res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map); + if (res) + res->flags = flags; res = isl_basic_map_finalize(res); return res; error: @@ -9153,6 +9830,60 @@ __isl_give isl_set *isl_set_align_params(__isl_take isl_set *set, return isl_map_align_params(set, model); } +/* Align the parameters of "bmap" to those of "model", introducing + * additional parameters if needed. + */ +__isl_give isl_basic_map *isl_basic_map_align_params( + __isl_take isl_basic_map *bmap, __isl_take isl_space *model) +{ + isl_ctx *ctx; + + if (!bmap || !model) + goto error; + + ctx = isl_space_get_ctx(model); + if (!isl_space_has_named_params(model)) + isl_die(ctx, isl_error_invalid, + "model has unnamed parameters", goto error); + if (!isl_space_has_named_params(bmap->dim)) + isl_die(ctx, isl_error_invalid, + "relation has unnamed parameters", goto error); + if (!isl_space_match(bmap->dim, isl_dim_param, model, isl_dim_param)) { + isl_reordering *exp; + struct isl_dim_map *dim_map; + + model = isl_space_drop_dims(model, isl_dim_in, + 0, isl_space_dim(model, isl_dim_in)); + model = isl_space_drop_dims(model, isl_dim_out, + 0, isl_space_dim(model, isl_dim_out)); + exp = isl_parameter_alignment_reordering(bmap->dim, model); + exp = isl_reordering_extend_space(exp, + isl_basic_map_get_space(bmap)); + dim_map = isl_dim_map_from_reordering(exp); + bmap = isl_basic_map_realign(bmap, + exp ? isl_space_copy(exp->dim) : NULL, + isl_dim_map_extend(dim_map, bmap)); + isl_reordering_free(exp); + free(dim_map); + } + + isl_space_free(model); + return bmap; +error: + isl_space_free(model); + isl_basic_map_free(bmap); + return NULL; +} + +/* Align the parameters of "bset" to those of "model", introducing + * additional parameters if needed. + */ +__isl_give isl_basic_set *isl_basic_set_align_params( + __isl_take isl_basic_set *bset, __isl_take isl_space *model) +{ + return isl_basic_map_align_params(bset, model); +} + __isl_give isl_mat *isl_basic_map_equalities_matrix( __isl_keep isl_basic_map *bmap, enum isl_dim_type c1, enum isl_dim_type c2, enum isl_dim_type c3, @@ -9350,6 +10081,7 @@ __isl_give isl_basic_map *isl_basic_map_zip(__isl_take isl_basic_map *bmap) isl_space_dim(bmap->dim->nested[0], isl_dim_in); n1 = isl_space_dim(bmap->dim->nested[0], isl_dim_out); n2 = isl_space_dim(bmap->dim->nested[1], isl_dim_in); + bmap = isl_basic_map_cow(bmap); bmap = isl_basic_map_swap_vars(bmap, pos, n1, n2); if (!bmap) return NULL; @@ -9396,6 +10128,83 @@ error: return NULL; } +/* Can we apply isl_basic_map_curry to "bmap"? + * That is, does it have a nested relation in its domain? + */ +int isl_basic_map_can_curry(__isl_keep isl_basic_map *bmap) +{ + if (!bmap) + return -1; + + return isl_space_can_curry(bmap->dim); +} + +/* Can we apply isl_map_curry to "map"? + * That is, does it have a nested relation in its domain? + */ +int isl_map_can_curry(__isl_keep isl_map *map) +{ + if (!map) + return -1; + + return isl_space_can_curry(map->dim); +} + +/* Given a basic map (A -> B) -> C, return the corresponding basic map + * A -> (B -> C). + */ +__isl_give isl_basic_map *isl_basic_map_curry(__isl_take isl_basic_map *bmap) +{ + + if (!bmap) + return NULL; + + if (!isl_basic_map_can_curry(bmap)) + isl_die(bmap->ctx, isl_error_invalid, + "basic map cannot be curried", goto error); + bmap->dim = isl_space_curry(bmap->dim); + if (!bmap->dim) + goto error; + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Given a map (A -> B) -> C, return the corresponding map + * A -> (B -> C). + */ +__isl_give isl_map *isl_map_curry(__isl_take isl_map *map) +{ + int i; + + if (!map) + return NULL; + + if (!isl_map_can_curry(map)) + isl_die(map->ctx, isl_error_invalid, "map cannot be curried", + goto error); + + map = isl_map_cow(map); + if (!map) + return NULL; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_curry(map->p[i]); + if (!map->p[i]) + goto error; + } + + map->dim = isl_space_curry(map->dim); + if (!map->dim) + goto error; + + return map; +error: + isl_map_free(map); + return NULL; +} + /* Construct a basic map mapping the domain of the affine expression * to a one-dimensional range prescribed by the affine expression. */ @@ -9410,8 +10219,6 @@ __isl_give isl_basic_map *isl_basic_map_from_aff(__isl_take isl_aff *aff) return NULL; ls = isl_aff_get_local_space(aff); - ls = isl_local_space_from_domain(ls); - ls = isl_local_space_add_dims(ls, isl_dim_out, 1); bmap = isl_basic_map_from_local_space(ls); bmap = isl_basic_map_extend_constraints(bmap, 1, 0); k = isl_basic_map_alloc_equality(bmap); @@ -9433,6 +10240,66 @@ error: return NULL; } +/* Construct a map mapping the domain of the affine expression + * to a one-dimensional range prescribed by the affine expression. + */ +__isl_give isl_map *isl_map_from_aff(__isl_take isl_aff *aff) +{ + isl_basic_map *bmap; + + bmap = isl_basic_map_from_aff(aff); + return isl_map_from_basic_map(bmap); +} + +/* Construct a basic map mapping the domain the multi-affine expression + * to its range, with each dimension in the range equated to the + * corresponding affine expression. + */ +__isl_give isl_basic_map *isl_basic_map_from_multi_aff( + __isl_take isl_multi_aff *maff) +{ + int i; + isl_space *space; + isl_basic_map *bmap; + + if (!maff) + return NULL; + + if (isl_space_dim(maff->space, isl_dim_out) != maff->n) + isl_die(isl_multi_aff_get_ctx(maff), isl_error_internal, + "invalid space", return isl_multi_aff_free(maff)); + + space = isl_space_domain(isl_multi_aff_get_space(maff)); + bmap = isl_basic_map_universe(isl_space_from_domain(space)); + + for (i = 0; i < maff->n; ++i) { + isl_aff *aff; + isl_basic_map *bmap_i; + + aff = isl_aff_copy(maff->p[i]); + bmap_i = isl_basic_map_from_aff(aff); + + bmap = isl_basic_map_flat_range_product(bmap, bmap_i); + } + + bmap = isl_basic_map_reset_space(bmap, isl_multi_aff_get_space(maff)); + + isl_multi_aff_free(maff); + return bmap; +} + +/* Construct a map mapping the domain the multi-affine expression + * to its range, with each dimension in the range equated to the + * corresponding affine expression. + */ +__isl_give isl_map *isl_map_from_multi_aff(__isl_take isl_multi_aff *maff) +{ + isl_basic_map *bmap; + + bmap = isl_basic_map_from_multi_aff(maff); + return isl_map_from_basic_map(bmap); +} + /* Construct a basic map mapping a domain in the given space to * to an n-dimensional range, with n the number of elements in the list, * where each coordinate in the range is prescribed by the @@ -9473,11 +10340,78 @@ __isl_give isl_set *isl_set_equate(__isl_take isl_set *set, return isl_map_equate(set, type1, pos1, type2, pos2); } +/* Construct a basic map where the given dimensions are equal to each other. + */ +static __isl_give isl_basic_map *equator(__isl_take isl_space *space, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + isl_basic_map *bmap = NULL; + int i; + + if (!space) + return NULL; + + if (pos1 >= isl_space_dim(space, type1)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "index out of bounds", goto error); + if (pos2 >= isl_space_dim(space, type2)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "index out of bounds", goto error); + + if (type1 == type2 && pos1 == pos2) + return isl_basic_map_universe(space); + + bmap = isl_basic_map_alloc_space(isl_space_copy(space), 0, 1, 0); + i = isl_basic_map_alloc_equality(bmap); + if (i < 0) + goto error; + isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap)); + pos1 += isl_basic_map_offset(bmap, type1); + pos2 += isl_basic_map_offset(bmap, type2); + isl_int_set_si(bmap->eq[i][pos1], -1); + isl_int_set_si(bmap->eq[i][pos2], 1); + bmap = isl_basic_map_finalize(bmap); + isl_space_free(space); + return bmap; +error: + isl_space_free(space); + isl_basic_map_free(bmap); + return NULL; +} + +/* Add a constraint imposing that the given two dimensions are equal. + */ +__isl_give isl_basic_map *isl_basic_map_equate(__isl_take isl_basic_map *bmap, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + isl_basic_map *eq; + + eq = equator(isl_basic_map_get_space(bmap), type1, pos1, type2, pos2); + + bmap = isl_basic_map_intersect(bmap, eq); + + return bmap; +} + /* Add a constraint imposing that the given two dimensions are equal. */ __isl_give isl_map *isl_map_equate(__isl_take isl_map *map, enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) { + isl_basic_map *bmap; + + bmap = equator(isl_map_get_space(map), type1, pos1, type2, pos2); + + map = isl_map_intersect(map, isl_map_from_basic_map(bmap)); + + return map; +} + +/* Add a constraint imposing that the given two dimensions have opposite values. + */ +__isl_give isl_map *isl_map_oppose(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ isl_basic_map *bmap = NULL; int i; @@ -9498,7 +10432,7 @@ __isl_give isl_map *isl_map_equate(__isl_take isl_map *map, isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap)); pos1 += isl_basic_map_offset(bmap, type1); pos2 += isl_basic_map_offset(bmap, type2); - isl_int_set_si(bmap->eq[i][pos1], -1); + isl_int_set_si(bmap->eq[i][pos1], 1); isl_int_set_si(bmap->eq[i][pos2], 1); bmap = isl_basic_map_finalize(bmap); @@ -9511,9 +10445,10 @@ error: return NULL; } -/* Add a constraint imposing that the given two dimensions have opposite values. +/* Add a constraint imposing that the value of the first dimension is + * greater than that of the second. */ -__isl_give isl_map *isl_map_oppose(__isl_take isl_map *map, +__isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map, enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) { isl_basic_map *bmap = NULL; @@ -9529,15 +10464,22 @@ __isl_give isl_map *isl_map_oppose(__isl_take isl_map *map, isl_die(map->ctx, isl_error_invalid, "index out of bounds", goto error); - bmap = isl_basic_map_alloc_space(isl_map_get_space(map), 0, 1, 0); - i = isl_basic_map_alloc_equality(bmap); + if (type1 == type2 && pos1 == pos2) { + isl_space *space = isl_map_get_space(map); + isl_map_free(map); + return isl_map_empty(space); + } + + bmap = isl_basic_map_alloc_space(isl_map_get_space(map), 0, 0, 1); + i = isl_basic_map_alloc_inequality(bmap); if (i < 0) goto error; - isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap)); + isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap)); pos1 += isl_basic_map_offset(bmap, type1); pos2 += isl_basic_map_offset(bmap, type2); - isl_int_set_si(bmap->eq[i][pos1], 1); - isl_int_set_si(bmap->eq[i][pos2], 1); + isl_int_set_si(bmap->ineq[i][pos1], 1); + isl_int_set_si(bmap->ineq[i][pos2], -1); + isl_int_set_si(bmap->ineq[i][0], -1); bmap = isl_basic_map_finalize(bmap); map = isl_map_intersect(map, isl_map_from_basic_map(bmap)); @@ -9548,3 +10490,151 @@ error: isl_map_free(map); return NULL; } + +/* Add a constraint imposing that the value of the first dimension is + * smaller than that of the second. + */ +__isl_give isl_map *isl_map_order_lt(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + return isl_map_order_gt(map, type2, pos2, type1, pos1); +} + +__isl_give isl_aff *isl_basic_map_get_div(__isl_keep isl_basic_map *bmap, + int pos) +{ + isl_aff *div; + isl_local_space *ls; + + if (!bmap) + return NULL; + + if (!isl_basic_map_divs_known(bmap)) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, + "some divs are unknown", return NULL); + + ls = isl_basic_map_get_local_space(bmap); + div = isl_local_space_get_div(ls, pos); + isl_local_space_free(ls); + + return div; +} + +__isl_give isl_aff *isl_basic_set_get_div(__isl_keep isl_basic_set *bset, + int pos) +{ + return isl_basic_map_get_div(bset, pos); +} + +/* Plug in "subs" for dimension "type", "pos" of "bset". + * + * Let i be the dimension to replace and let "subs" be of the form + * + * f/d + * + * Any integer division with a non-zero coefficient for i, + * + * floor((a i + g)/m) + * + * is replaced by + * + * floor((a f + d g)/(m d)) + * + * Constraints of the form + * + * a i + g + * + * are replaced by + * + * a f + d g + */ +__isl_give isl_basic_set *isl_basic_set_substitute( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs) +{ + int i; + isl_int v; + isl_ctx *ctx; + + if (bset && isl_basic_set_plain_is_empty(bset)) + return bset; + + bset = isl_basic_set_cow(bset); + if (!bset || !subs) + goto error; + + ctx = isl_basic_set_get_ctx(bset); + if (!isl_space_is_equal(bset->dim, subs->ls->dim)) + isl_die(ctx, isl_error_invalid, + "spaces don't match", goto error); + if (isl_local_space_dim(subs->ls, isl_dim_div) != 0) + isl_die(ctx, isl_error_unsupported, + "cannot handle divs yet", goto error); + + pos += isl_basic_set_offset(bset, type); + + isl_int_init(v); + + for (i = 0; i < bset->n_eq; ++i) { + if (isl_int_is_zero(bset->eq[i][pos])) + continue; + isl_int_set(v, bset->eq[i][pos]); + isl_int_set_si(bset->eq[i][pos], 0); + isl_seq_combine(bset->eq[i], subs->v->el[0], bset->eq[i], + v, subs->v->el + 1, subs->v->size - 1); + } + + for (i = 0; i < bset->n_ineq; ++i) { + if (isl_int_is_zero(bset->ineq[i][pos])) + continue; + isl_int_set(v, bset->ineq[i][pos]); + isl_int_set_si(bset->ineq[i][pos], 0); + isl_seq_combine(bset->ineq[i], subs->v->el[0], bset->ineq[i], + v, subs->v->el + 1, subs->v->size - 1); + } + + for (i = 0; i < bset->n_div; ++i) { + if (isl_int_is_zero(bset->div[i][1 + pos])) + continue; + isl_int_set(v, bset->div[i][1 + pos]); + isl_int_set_si(bset->div[i][1 + pos], 0); + isl_seq_combine(bset->div[i] + 1, + subs->v->el[0], bset->div[i] + 1, + v, subs->v->el + 1, subs->v->size - 1); + isl_int_mul(bset->div[i][0], bset->div[i][0], subs->v->el[0]); + } + + isl_int_clear(v); + + bset = isl_basic_set_simplify(bset); + return isl_basic_set_finalize(bset); +error: + isl_basic_set_free(bset); + return NULL; +} + +/* Plug in "subs" for dimension "type", "pos" of "set". + */ +__isl_give isl_set *isl_set_substitute(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs) +{ + int i; + + if (set && isl_set_plain_is_empty(set)) + return set; + + set = isl_set_cow(set); + if (!set || !subs) + goto error; + + for (i = set->n - 1; i >= 0; --i) { + set->p[i] = isl_basic_set_substitute(set->p[i], type, pos, subs); + if (remove_if_empty(set, i) < 0) + goto error; + } + + return set; +error: + isl_set_free(set); + return NULL; +}