X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;ds=sidebyside;f=isl_map.c;h=9a5f5ea175f38281a94a8632b6adf51c7d3155d1;hb=303faf2984bf54cdedca8d984cf9c848b556415e;hp=c364bafb6e2b91b9903fac1261e4514d840c5b31;hpb=6fa62d808e896358f380032ee208cbc2851ca485;p=platform%2Fupstream%2Fisl.git diff --git a/isl_map.c b/isl_map.c index c364baf..9a5f5ea 100644 --- a/isl_map.c +++ b/isl_map.c @@ -1,13 +1,15 @@ /* * 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 + * Use of this software is governed by the MIT license * * Written by Sven Verdoolaege, K.U.Leuven, Departement * 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 @@ -406,6 +408,13 @@ error: return NULL; } +/* Does the input or output tuple have a name? + */ +int isl_map_has_tuple_name(__isl_keep isl_map *map, enum isl_dim_type type) +{ + return map ? isl_space_has_tuple_name(map->dim, type) : -1; +} + const char *isl_map_get_tuple_name(__isl_keep isl_map *map, enum isl_dim_type type) { @@ -504,6 +513,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) { @@ -534,7 +551,7 @@ __isl_give isl_basic_map *isl_basic_map_set_dim_name( 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; @@ -585,6 +602,12 @@ int isl_basic_map_has_dim_id(__isl_keep isl_basic_map *bmap, 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) { @@ -903,13 +926,13 @@ struct isl_map *isl_map_copy(struct isl_map *map) return map; } -void isl_basic_map_free(struct isl_basic_map *bmap) +void *isl_basic_map_free(__isl_take isl_basic_map *bmap) { if (!bmap) - return; + return NULL; if (--bmap->ref > 0) - return; + return NULL; isl_ctx_deref(bmap->ctx); free(bmap->div); @@ -919,11 +942,13 @@ void isl_basic_map_free(struct isl_basic_map *bmap) isl_vec_free(bmap->sample); isl_space_free(bmap->dim); free(bmap); + + return NULL; } -void isl_basic_set_free(struct isl_basic_set *bset) +void *isl_basic_set_free(struct isl_basic_set *bset) { - isl_basic_map_free((struct isl_basic_map *)bset); + return isl_basic_map_free((struct isl_basic_map *)bset); } static int room_for_con(struct isl_basic_map *bmap, unsigned n) @@ -1588,8 +1613,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) @@ -1601,6 +1626,10 @@ __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; @@ -1617,8 +1646,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) @@ -1627,8 +1656,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) @@ -1731,6 +1760,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. */ @@ -1749,6 +1968,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; @@ -1761,6 +1981,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) { @@ -2260,21 +2487,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) @@ -2594,10 +2823,9 @@ static __isl_give isl_map *map_intersect_internal(__isl_take isl_map *map1, part = isl_basic_map_intersect( isl_basic_map_copy(map1->p[i]), isl_basic_map_copy(map2->p[j])); - if (isl_basic_map_is_empty(part)) - isl_basic_map_free(part); - else - result = isl_map_add_basic_map(result, part); + if (isl_basic_map_is_empty(part) < 0) + goto error; + result = isl_map_add_basic_map(result, part); if (!result) goto error; } @@ -2691,8 +2919,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; @@ -2737,12 +2966,19 @@ __isl_give isl_basic_map *isl_basic_map_insert(__isl_take isl_basic_map *bmap, 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); } @@ -2789,7 +3025,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; } @@ -4823,21 +5059,23 @@ error: return NULL; } -void isl_map_free(struct isl_map *map) +void *isl_map_free(struct isl_map *map) { int i; if (!map) - return; + return NULL; if (--map->ref > 0) - return; + return NULL; isl_ctx_deref(map->ctx); for (i = 0; i < map->n; ++i) isl_basic_map_free(map->p[i]); isl_space_free(map->dim); free(map); + + return NULL; } struct isl_map *isl_map_extend(struct isl_map *base, @@ -5390,58 +5628,93 @@ __isl_give isl_pw_multi_aff *isl_basic_map_lexmin_pw_multi_aff( return isl_basic_map_lexopt_pw_multi_aff(bmap, 0); } -/* Given a basic map "bmap", compute the lexicographically minimal - * (or maximal) image element for each domain element in dom. +#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. @@ -5450,7 +5723,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. @@ -5569,35 +5842,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) @@ -5665,31 +5909,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); @@ -6568,7 +6787,7 @@ error: return NULL; } -__isl_give struct isl_basic_map *basic_map_identity(__isl_take isl_space *dims) +static __isl_give isl_basic_map *basic_map_identity(__isl_take isl_space *dims) { struct isl_basic_map *bmap; unsigned nparam; @@ -8249,6 +8468,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)); @@ -8816,7 +9040,7 @@ int isl_set_dim_is_bounded(__isl_keep isl_set *set, return isl_map_dim_is_bounded((isl_map *)set, type, pos); } -static int has_bound(__isl_keep isl_map *map, +static int has_any_bound(__isl_keep isl_map *map, enum isl_dim_type type, unsigned pos, int (*fn)(__isl_keep isl_basic_map *bmap, enum isl_dim_type type, unsigned pos)) @@ -8838,18 +9062,20 @@ static int has_bound(__isl_keep isl_map *map, /* Return 1 if the specified dim is involved in any lower bound. */ -int isl_set_dim_has_lower_bound(__isl_keep isl_set *set, +int isl_set_dim_has_any_lower_bound(__isl_keep isl_set *set, enum isl_dim_type type, unsigned pos) { - return has_bound(set, type, pos, &isl_basic_map_dim_has_lower_bound); + return has_any_bound(set, type, pos, + &isl_basic_map_dim_has_lower_bound); } /* Return 1 if the specified dim is involved in any upper bound. */ -int isl_set_dim_has_upper_bound(__isl_keep isl_set *set, +int isl_set_dim_has_any_upper_bound(__isl_keep isl_set *set, enum isl_dim_type type, unsigned pos) { - return has_bound(set, type, pos, &isl_basic_map_dim_has_upper_bound); + return has_any_bound(set, type, pos, + &isl_basic_map_dim_has_upper_bound); } /* For each of the "n" variables starting at "first", determine @@ -8962,6 +9188,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) @@ -9583,6 +9842,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, @@ -9780,6 +10093,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; @@ -10038,25 +10352,28 @@ __isl_give isl_set *isl_set_equate(__isl_take isl_set *set, return isl_map_equate(set, type1, pos1, type2, pos2); } -/* Add a constraint imposing that the given two dimensions are equal. +/* Construct a basic map where the given dimensions are equal to each other. */ -__isl_give isl_map *isl_map_equate(__isl_take isl_map *map, +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 (!map) + if (!space) return NULL; - if (pos1 >= isl_map_dim(map, type1)) - isl_die(map->ctx, isl_error_invalid, + 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_map_dim(map, type2)) - isl_die(map->ctx, isl_error_invalid, + if (pos2 >= isl_space_dim(space, type2)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, "index out of bounds", goto error); - bmap = isl_basic_map_alloc_space(isl_map_get_space(map), 0, 1, 0); + 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; @@ -10066,14 +10383,40 @@ __isl_give isl_map *isl_map_equate(__isl_take isl_map *map, 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; -error: - isl_basic_map_free(bmap); - isl_map_free(map); - return NULL; } /* Add a constraint imposing that the given two dimensions have opposite values. @@ -10115,6 +10458,37 @@ error: } /* Add a constraint imposing that the value of the first dimension is + * greater than or equal to that of the second. + */ +__isl_give isl_basic_map *isl_basic_map_order_ge(__isl_take isl_basic_map *bmap, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + isl_constraint *c; + isl_local_space *ls; + + if (!bmap) + return NULL; + + if (pos1 >= isl_basic_map_dim(bmap, type1)) + isl_die(bmap->ctx, isl_error_invalid, + "index out of bounds", return isl_basic_map_free(bmap)); + if (pos2 >= isl_basic_map_dim(bmap, type2)) + isl_die(bmap->ctx, isl_error_invalid, + "index out of bounds", return isl_basic_map_free(bmap)); + + if (type1 == type2 && pos1 == pos2) + return bmap; + + ls = isl_local_space_from_space(isl_basic_map_get_space(bmap)); + c = isl_inequality_alloc(ls); + c = isl_constraint_set_coefficient_si(c, type1, pos1, 1); + c = isl_constraint_set_coefficient_si(c, type2, pos2, -1); + bmap = isl_basic_map_add_constraint(bmap, c); + + return bmap; +} + +/* Add a constraint imposing that the value of the first dimension is * greater than that of the second. */ __isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map, @@ -10133,6 +10507,12 @@ __isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map, isl_die(map->ctx, isl_error_invalid, "index out of bounds", goto error); + 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) @@ -10154,6 +10534,15 @@ error: 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) {