/*
* 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
*
* 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 <string.h>
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;
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;
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)
{
}
/* 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)
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;
}
/* 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)
}
/* 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)
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.
*/
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;
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));
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)
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;
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.
*/
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;
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);
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;
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));
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)
{