/*
* Copyright 2008-2009 Katholieke Universiteit Leuven
+ * 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 Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
*/
#include <strings.h>
(struct isl_basic_map *)bset);
}
+/* Remove any common factor in numerator and denominator of the div expression,
+ * not taking into account the constant term.
+ * That is, if the div is of the form
+ *
+ * floor((a + m f(x))/(m d))
+ *
+ * then replace it by
+ *
+ * floor((floor(a/m) + f(x))/d)
+ *
+ * The difference {a/m}/d in the argument satisfies 0 <= {a/m}/d < 1/d
+ * and can therefore not influence the result of the floor.
+ */
+static void normalize_div_expression(__isl_keep isl_basic_map *bmap, int div)
+{
+ unsigned total = isl_basic_map_total_dim(bmap);
+ isl_ctx *ctx = bmap->ctx;
+
+ if (isl_int_is_zero(bmap->div[div][0]))
+ return;
+ isl_seq_gcd(bmap->div[div] + 2, total, &ctx->normalize_gcd);
+ isl_int_gcd(ctx->normalize_gcd, ctx->normalize_gcd, bmap->div[div][0]);
+ if (isl_int_is_one(ctx->normalize_gcd))
+ return;
+ isl_int_fdiv_q(bmap->div[div][1], bmap->div[div][1],
+ ctx->normalize_gcd);
+ isl_int_divexact(bmap->div[div][0], bmap->div[div][0],
+ ctx->normalize_gcd);
+ isl_seq_scale_down(bmap->div[div] + 2, bmap->div[div] + 2,
+ ctx->normalize_gcd, total);
+}
+
+/* Remove any common factor in numerator and denominator of a div expression,
+ * not taking into account the constant term.
+ * That is, look for any div of the form
+ *
+ * floor((a + m f(x))/(m d))
+ *
+ * and replace it by
+ *
+ * floor((floor(a/m) + f(x))/d)
+ *
+ * The difference {a/m}/d in the argument satisfies 0 <= {a/m}/d < 1/d
+ * and can therefore not influence the result of the floor.
+ */
+static __isl_give isl_basic_map *normalize_div_expressions(
+ __isl_take isl_basic_map *bmap)
+{
+ int i;
+
+ if (!bmap)
+ return NULL;
+ if (bmap->n_div == 0)
+ return bmap;
+
+ for (i = 0; i < bmap->n_div; ++i)
+ normalize_div_expression(bmap, i);
+
+ return bmap;
+}
+
/* Assumes divs have been ordered if keep_divs is set.
*/
static void eliminate_var_using_equality(struct isl_basic_map *bmap,
* and we can keep the definition as long as the result
* is still ordered.
*/
- if (last_div == -1 || (keep_divs && last_div < k))
+ if (last_div == -1 || (keep_divs && last_div < k)) {
isl_seq_elim(bmap->div[k]+1, eq,
1+pos, 1+total, &bmap->div[k][0]);
- else
+ normalize_div_expression(bmap, k);
+ } else
isl_seq_clr(bmap->div[k], 1 + total);
ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
}
unsigned total;
struct isl_ctx *ctx;
+ bmap = isl_basic_map_order_divs(bmap);
if (!bmap || bmap->n_div <= 1)
return bmap;
k = elim_for[l] - 1;
isl_int_set_si(eq.data[1+total_var+k], -1);
isl_int_set_si(eq.data[1+total_var+l], 1);
- eliminate_div(bmap, eq.data, l, 0);
+ eliminate_div(bmap, eq.data, l, 1);
isl_int_set_si(eq.data[1+total_var+k], 0);
isl_int_set_si(eq.data[1+total_var+l], 0);
}
}
+/* Eliminate knowns divs from constraints where they appear with
+ * a (positive or negative) unit coefficient.
+ *
+ * That is, replace
+ *
+ * floor(e/m) + f >= 0
+ *
+ * by
+ *
+ * e + m f >= 0
+ *
+ * and
+ *
+ * -floor(e/m) + f >= 0
+ *
+ * by
+ *
+ * -e + m f + m - 1 >= 0
+ *
+ * The first conversion is valid because floor(e/m) >= -f is equivalent
+ * to e/m >= -f because -f is an integral expression.
+ * The second conversion follows from the fact that
+ *
+ * -floor(e/m) = ceil(-e/m) = floor((-e + m - 1)/m)
+ *
+ *
+ * We skip integral divs, i.e., those with denominator 1, as we would
+ * risk eliminating the div from the div constraints. We do not need
+ * to handle those divs here anyway since the div constraints will turn
+ * out to form an equality and this equality can then be use to eliminate
+ * the div from all constraints.
+ */
+static __isl_give isl_basic_map *eliminate_unit_divs(
+ __isl_take isl_basic_map *bmap, int *progress)
+{
+ int i, j;
+ isl_ctx *ctx;
+ unsigned total;
+
+ if (!bmap)
+ return NULL;
+
+ ctx = isl_basic_map_get_ctx(bmap);
+ total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+ for (i = 0; i < bmap->n_div; ++i) {
+ if (isl_int_is_zero(bmap->div[i][0]))
+ continue;
+ if (isl_int_is_one(bmap->div[i][0]))
+ continue;
+ for (j = 0; j < bmap->n_ineq; ++j) {
+ int s;
+
+ if (!isl_int_is_one(bmap->ineq[j][total + i]) &&
+ !isl_int_is_negone(bmap->ineq[j][total + i]))
+ continue;
+
+ *progress = 1;
+
+ s = isl_int_sgn(bmap->ineq[j][total + i]);
+ isl_int_set_si(bmap->ineq[j][total + i], 0);
+ if (s < 0)
+ isl_seq_combine(bmap->ineq[j],
+ ctx->negone, bmap->div[i] + 1,
+ bmap->div[i][0], bmap->ineq[j],
+ total + bmap->n_div);
+ else
+ isl_seq_combine(bmap->ineq[j],
+ ctx->one, bmap->div[i] + 1,
+ bmap->div[i][0], bmap->ineq[j],
+ total + bmap->n_div);
+ if (s < 0) {
+ isl_int_add(bmap->ineq[j][0],
+ bmap->ineq[j][0], bmap->div[i][0]);
+ isl_int_sub_ui(bmap->ineq[j][0],
+ bmap->ineq[j][0], 1);
+ }
+ }
+ }
+
+ return bmap;
+}
+
struct isl_basic_map *isl_basic_map_simplify(struct isl_basic_map *bmap)
{
int progress = 1;
while (progress) {
progress = 0;
bmap = isl_basic_map_normalize_constraints(bmap);
+ bmap = normalize_div_expressions(bmap);
bmap = remove_duplicate_divs(bmap, &progress);
+ bmap = eliminate_unit_divs(bmap, &progress);
bmap = eliminate_divs_eq(bmap, &progress);
bmap = eliminate_divs_ineq(bmap, &progress);
bmap = isl_basic_map_gauss(bmap, &progress);
return 1;
}
+int isl_basic_set_is_div_constraint(__isl_keep isl_basic_set *bset,
+ isl_int *constraint, unsigned div)
+{
+ return isl_basic_map_is_div_constraint(bset, constraint, div);
+}
+
/* If the only constraints a div d=floor(f/m)
* appears in are its two defining constraints
}
/* 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.
+ * Otherwise, they are projected out and the original space is restored.
*/
__isl_give isl_basic_map *isl_basic_map_eliminate(
__isl_take isl_basic_map *bmap,
enum isl_dim_type type, unsigned first, unsigned n)
{
+ isl_space *space;
+
if (!bmap)
return NULL;
if (n == 0)
return bmap;
- if (first + n > isl_basic_map_dim(bmap, type))
+ if (first + n > isl_basic_map_dim(bmap, type) || first + n < first)
isl_die(bmap->ctx, isl_error_invalid,
"index out of bounds", goto error);
- first += isl_basic_map_offset(bmap, type) - 1;
- bmap = isl_basic_map_eliminate_vars(bmap, first, n);
- return isl_basic_map_finalize(bmap);
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) {
+ first += isl_basic_map_offset(bmap, type) - 1;
+ bmap = isl_basic_map_eliminate_vars(bmap, first, n);
+ return isl_basic_map_finalize(bmap);
+ }
+
+ space = isl_basic_map_get_space(bmap);
+ bmap = isl_basic_map_project_out(bmap, type, first, n);
+ bmap = isl_basic_map_insert_dims(bmap, type, first, n);
+ bmap = isl_basic_map_reset_space(bmap, space);
+ return bmap;
error:
isl_basic_map_free(bmap);
return NULL;
}
+__isl_give isl_basic_set *isl_basic_set_eliminate(
+ __isl_take isl_basic_set *bset,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ return isl_basic_map_eliminate(bset, type, first, n);
+}
+
/* Don't assume equalities are in order, because align_divs
* may have changed the order of the divs.
*/
/* Remove divs that are not strictly needed.
* In particular, if a div only occurs positively (or negatively)
* in constraints, then it can simply be dropped.
- * Also, if a div occurs only occurs in two constraints and if moreover
+ * Also, if a div occurs in only two constraints and if moreover
* those two constraints are opposite to each other, except for the constant
* term and if the sum of the constant terms is such that for any value
* of the other values, there is always at least one integer value of the
* the (absolute value) of the coefficent of the div in the constraints,
* then we can also simply drop the div.
*
+ * We skip divs that appear in equalities or in the definition of other divs.
+ * Divs that appear in the definition of other divs usually occur in at least
+ * 4 constraints, but the constraints may have been simplified.
+ *
* If any divs are left after these simple checks then we move on
* to more complicated cases in drop_more_redundant_divs.
*/
int defined;
defined = !isl_int_is_zero(bmap->div[i][0]);
+ for (j = i; j < bmap->n_div; ++j)
+ if (!isl_int_is_zero(bmap->div[j][1 + 1 + off + i]))
+ break;
+ if (j < bmap->n_div)
+ continue;
for (j = 0; j < bmap->n_eq; ++j)
if (!isl_int_is_zero(bmap->eq[j][1 + off + i]))
break;