+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the GNU LGPLv2.1 license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
#include "isl_mat.h"
#include "isl_map_private.h"
#include "isl_tab.h"
static void swap_rows(struct isl_tab *tab, int row1, int row2)
{
int t;
+ enum isl_tab_row_sign s;
+
t = tab->row_var[row1];
tab->row_var[row1] = tab->row_var[row2];
tab->row_var[row2] = t;
if (!tab->row_sign)
return;
- t = tab->row_sign[row1];
+ s = tab->row_sign[row1];
tab->row_sign[row1] = tab->row_sign[row2];
- tab->row_sign[row2] = t;
+ tab->row_sign[row2] = s;
}
static int push_union(struct isl_tab *tab,
if (tab->empty)
return;
- for (i = 0; i < tab->n_row; ++i) {
- if (!isl_tab_var_from_row(tab, i)->is_nonneg)
+ for (i = tab->n_redundant; i < tab->n_row; ++i) {
+ struct isl_tab_var *var;
+ var = isl_tab_var_from_row(tab, i);
+ if (!var->is_nonneg)
continue;
+ if (tab->M) {
+ assert(!isl_int_is_neg(tab->mat->row[i][2]));
+ if (isl_int_is_pos(tab->mat->row[i][2]))
+ continue;
+ }
assert(!isl_int_is_neg(tab->mat->row[i][1]));
}
}
* Return 0 otherwise.
*
* The sample value of "var" is assumed to be non-negative when the
- * the function is called and will be made non-negative again before
+ * the function is called. If 1 is returned then the constraint
+ * is not redundant and the sample value is made non-negative again before
* the function returns.
*/
int isl_tab_min_at_most_neg_one(struct isl_tab *tab, struct isl_tab_var *var)
return 0;
do {
find_pivot(tab, var, var, -1, &row, &col);
- if (row == var->index)
+ if (row == var->index) {
+ if (restore_row(tab, var) < -1)
+ return -1;
return 1;
+ }
if (row == -1)
return 0;
pivot_var = var_from_col(tab, col);
isl_int_clear(b);
if (tab->row_sign)
- tab->row_sign[tab->con[r].index] = 0;
+ tab->row_sign[tab->con[r].index] = isl_tab_row_unknown;
return r;
}
return NULL;
}
+/* Construct and return an inequality that expresses an upper bound
+ * on the given div.
+ * In particular, if the div is given by
+ *
+ * d = floor(e/m)
+ *
+ * then the inequality expresses
+ *
+ * m d <= e
+ */
+static struct isl_vec *ineq_for_div(struct isl_basic_map *bmap, unsigned div)
+{
+ unsigned total;
+ unsigned div_pos;
+ struct isl_vec *ineq;
+
+ if (!bmap)
+ return NULL;
+
+ total = isl_basic_map_total_dim(bmap);
+ div_pos = 1 + total - bmap->n_div + div;
+
+ ineq = isl_vec_alloc(bmap->ctx, 1 + total);
+ if (!ineq)
+ return NULL;
+
+ isl_seq_cpy(ineq->el, bmap->div[div] + 1, 1 + total);
+ isl_int_neg(ineq->el[div_pos], bmap->div[div][0]);
+ return ineq;
+}
+
+/* For a div d = floor(f/m), add the constraints
+ *
+ * f - m d >= 0
+ * -(f-(m-1)) + m d >= 0
+ *
+ * Note that the second constraint is the negation of
+ *
+ * f - m d >= m
+ *
+ * If add_ineq is not NULL, then this function is used
+ * instead of isl_tab_add_ineq to effectively add the inequalities.
+ */
+static int add_div_constraints(struct isl_tab *tab, unsigned div,
+ int (*add_ineq)(void *user, isl_int *), void *user)
+{
+ unsigned total;
+ unsigned div_pos;
+ struct isl_vec *ineq;
+
+ total = isl_basic_map_total_dim(tab->bmap);
+ div_pos = 1 + total - tab->bmap->n_div + div;
+
+ ineq = ineq_for_div(tab->bmap, div);
+ if (!ineq)
+ goto error;
+
+ if (add_ineq) {
+ if (add_ineq(user, ineq->el) < 0)
+ goto error;
+ } else {
+ if (isl_tab_add_ineq(tab, ineq->el) < 0)
+ goto error;
+ }
+
+ isl_seq_neg(ineq->el, tab->bmap->div[div] + 1, 1 + total);
+ isl_int_set(ineq->el[div_pos], tab->bmap->div[div][0]);
+ isl_int_add(ineq->el[0], ineq->el[0], ineq->el[div_pos]);
+ isl_int_sub_ui(ineq->el[0], ineq->el[0], 1);
+
+ if (add_ineq) {
+ if (add_ineq(user, ineq->el) < 0)
+ goto error;
+ } else {
+ if (isl_tab_add_ineq(tab, ineq->el) < 0)
+ goto error;
+ }
+
+ isl_vec_free(ineq);
+
+ return 0;
+error:
+ isl_vec_free(ineq);
+ return -1;
+}
+
+/* Add an extra div, prescrived by "div" to the tableau and
+ * the associated bmap (which is assumed to be non-NULL).
+ *
+ * If add_ineq is not NULL, then this function is used instead
+ * of isl_tab_add_ineq to add the div constraints.
+ * This complication is needed because the code in isl_tab_pip
+ * wants to perform some extra processing when an inequality
+ * is added to the tableau.
+ */
+int isl_tab_add_div(struct isl_tab *tab, __isl_keep isl_vec *div,
+ int (*add_ineq)(void *user, isl_int *), void *user)
+{
+ int i;
+ int r;
+ int k;
+ int nonneg;
+
+ if (!tab || !div)
+ return -1;
+
+ isl_assert(tab->mat->ctx, tab->bmap, return -1);
+
+ for (i = 0; i < tab->n_var; ++i) {
+ if (isl_int_is_neg(div->el[2 + i]))
+ break;
+ if (isl_int_is_zero(div->el[2 + i]))
+ continue;
+ if (!tab->var[i].is_nonneg)
+ break;
+ }
+ nonneg = i == tab->n_var && !isl_int_is_neg(div->el[1]);
+
+ if (isl_tab_extend_cons(tab, 3) < 0)
+ return -1;
+ if (isl_tab_extend_vars(tab, 1) < 0)
+ return -1;
+ r = isl_tab_allocate_var(tab);
+ if (r < 0)
+ return -1;
+
+ if (nonneg)
+ tab->var[r].is_nonneg = 1;
+
+ tab->bmap = isl_basic_map_extend_dim(tab->bmap,
+ isl_basic_map_get_dim(tab->bmap), 1, 0, 2);
+ k = isl_basic_map_alloc_div(tab->bmap);
+ if (k < 0)
+ return -1;
+ isl_seq_cpy(tab->bmap->div[k], div->el, div->size);
+ if (isl_tab_push(tab, isl_tab_undo_bmap_div) < 0)
+ return -1;
+
+ if (add_div_constraints(tab, k, add_ineq, user) < 0)
+ return -1;
+
+ return r;
+}
+
struct isl_tab *isl_tab_from_basic_map(struct isl_basic_map *bmap)
{
int i;
else if (isl_tab_is_redundant(tab, n_eq + i))
isl_basic_map_drop_inequality(bmap, i);
}
+ if (bmap->n_eq != n_eq)
+ isl_basic_map_gauss(bmap, NULL);
if (!tab->rational &&
!bmap->sample && isl_tab_sample_is_integer(tab))
bmap->sample = extract_integer_sample(tab);
if (var->is_zero)
return tab;
isl_assert(tab->mat->ctx, !var->is_redundant, goto error);
+ isl_assert(tab->mat->ctx, var->is_nonneg, goto error);
if (isl_tab_extend_cons(tab, 1) < 0)
goto error;
* If r is a column variable, then we need to modify each row that
* refers to r = r' - 1 by substituting this equality, effectively
* subtracting the coefficient of the column from the constant.
+ * We should only do this if the minimum is manifestly unbounded,
+ * however. Otherwise, we may end up with negative sample values
+ * for non-negative variables.
+ * So, if r is a column variable with a minimum that is not
+ * manifestly unbounded, then we need to move it to a row.
+ * However, the sample value of this row may be negative,
+ * even after the relaxation, so we need to restore it.
+ * We therefore prefer to pivot a column up to a row, if possible.
*/
struct isl_tab *isl_tab_relax(struct isl_tab *tab, int con)
{
if (!var->is_row && !max_is_manifestly_unbounded(tab, var))
if (to_row(tab, var, 1) < 0)
goto error;
+ if (!var->is_row && !min_is_manifestly_unbounded(tab, var))
+ if (to_row(tab, var, -1) < 0)
+ goto error;
- if (var->is_row)
+ if (var->is_row) {
isl_int_add(tab->mat->row[var->index][1],
tab->mat->row[var->index][1], tab->mat->row[var->index][0]);
- else {
+ if (restore_row(tab, var) < 0)
+ goto error;
+ } else {
int i;
for (i = 0; i < tab->n_row; ++i) {
if (to_row(tab, var, 1) < 0)
return -1;
- if (var->is_row)
+ if (var->is_row) {
isl_int_sub(tab->mat->row[var->index][1],
tab->mat->row[var->index][1], tab->mat->row[var->index][0]);
- else {
+ if (var->is_nonneg) {
+ int sgn = restore_row(tab, var);
+ isl_assert(tab->mat->ctx, sgn >= 0, return -1);
+ }
+ } else {
int i;
for (i = 0; i < tab->n_row; ++i) {
case isl_tab_undo_redundant:
var->is_redundant = 0;
tab->n_redundant--;
+ restore_row(tab, isl_tab_var_from_row(tab, tab->n_redundant));
break;
case isl_tab_undo_freeze:
var->frozen = 0;