void *(*save)(struct isl_context *context);
/* restore saved context */
void (*restore)(struct isl_context *context, void *);
+ /* discard saved context */
+ void (*discard)(void *);
/* invalidate context */
void (*invalidate)(struct isl_context *context);
/* free context */
struct isl_tab *tab;
};
+/* A stack (linked list) of solutions of subtrees of the search space.
+ *
+ * "M" describes the solution in terms of the dimensions of "dom".
+ * The number of columns of "M" is one more than the total number
+ * of dimensions of "dom".
+ */
struct isl_partial_sol {
int level;
struct isl_basic_set *dom;
return;
error:
isl_basic_set_free(dom);
+ isl_mat_free(M);
sol->error = 1;
}
sol_pop_one(sol);
} else {
struct isl_basic_set *bset;
+ isl_mat *M;
+ unsigned n;
+ n = isl_basic_set_dim(partial->next->dom, isl_dim_div);
+ n -= n_div;
bset = sol_domain(sol);
-
isl_basic_set_free(partial->next->dom);
partial->next->dom = bset;
+ M = partial->next->M;
+ M = isl_mat_drop_cols(M, M->n_col - n, n);
+ partial->next->M = M;
partial->next->level = sol->level;
+ if (!bset || !M)
+ goto error;
+
sol->partial = partial->next;
isl_basic_set_free(partial->dom);
isl_mat_free(partial->M);
}
} else
sol_pop_one(sol);
+
+ if (0)
+error: sol->error = 1;
}
static void sol_dec_level(struct isl_sol *sol)
n = tab->n_div;
d = context->op->get_div(context, tab, div);
+ isl_vec_free(div);
if (d < 0)
return -1;
if (tab->row_sign)
tab->row_sign[tab->con[r].index] = isl_tab_row_neg;
- isl_vec_free(div);
-
row = tab->con[r].index;
if (d >= n && context->op->detect_equalities(context, tab) < 0)
}
}
+static void context_lex_discard(void *save)
+{
+}
+
static int context_lex_is_ok(struct isl_context *context)
{
struct isl_context_lex *clex = (struct isl_context_lex *)context;
context_lex_is_ok,
context_lex_save,
context_lex_restore,
+ context_lex_discard,
context_lex_invalidate,
context_lex_free,
};
return NULL;
}
+/* Representation of the context when using generalized basis reduction.
+ *
+ * "shifted" contains the offsets of the unit hypercubes that lie inside the
+ * context. Any rational point in "shifted" can therefore be rounded
+ * up to an integer point in the context.
+ * If the context is constrained by any equality, then "shifted" is not used
+ * as it would be empty.
+ */
struct isl_context_gbr {
struct isl_context context;
struct isl_tab *tab;
return NULL;
}
+/* Add the equality described by "eq" to the context.
+ * If "check" is set, then we check if the context is empty after
+ * adding the equality.
+ * If "update" is set, then we check if the samples are still valid.
+ *
+ * We do not explicitly add shifted copies of the equality to
+ * cgbr->shifted since they would conflict with each other.
+ * Instead, we directly mark cgbr->shifted empty.
+ */
static void context_gbr_add_eq(struct isl_context *context, isl_int *eq,
int check, int update)
{
cgbr->tab = add_gbr_eq(cgbr->tab, eq);
+ if (cgbr->shifted && !cgbr->shifted->empty && use_shifted(cgbr)) {
+ if (isl_tab_mark_empty(cgbr->shifted) < 0)
+ goto error;
+ }
+
if (cgbr->cone && cgbr->cone->n_col != cgbr->cone->n_dead) {
if (isl_tab_extend_cons(cgbr->cone, 2) < 0)
goto error;
n_ineq = cgbr->tab->bmap->n_ineq;
cgbr->tab = isl_tab_detect_equalities(cgbr->tab, cgbr->cone);
- if (cgbr->tab && cgbr->tab->bmap->n_ineq > n_ineq)
+ if (!cgbr->tab)
+ return -1;
+ if (cgbr->tab->bmap->n_ineq > n_ineq)
propagate_equalities(cgbr, tab, n_ineq);
return 0;
cgbr->tab = NULL;
}
+static void context_gbr_discard(void *save)
+{
+ struct isl_gbr_tab_undo *snap = (struct isl_gbr_tab_undo *)save;
+ free(snap);
+}
+
static int context_gbr_is_ok(struct isl_context *context)
{
struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
context_gbr_is_ok,
context_gbr_save,
context_gbr_restore,
+ context_gbr_discard,
context_gbr_invalidate,
context_gbr_free,
};
if (!sol->error)
sol->context->op->restore(sol->context, saved);
+ else
+ sol->context->op->discard(saved);
return;
error:
sol->error = 1;
sol->error = 1;
}
+/* Does "sol" contain a pair of partial solutions that could potentially
+ * be merged?
+ *
+ * We currently only check that "sol" is not in an error state
+ * and that there are at least two partial solutions of which the final two
+ * are defined at the same level.
+ */
+static int sol_has_mergeable_solutions(struct isl_sol *sol)
+{
+ if (sol->error)
+ return 0;
+ if (!sol->partial)
+ return 0;
+ if (!sol->partial->next)
+ return 0;
+ return sol->partial->level == sol->partial->next->level;
+}
+
/* Compute the lexicographic minimum of the set represented by the main
* tableau "tab" within the context "sol->context_tab".
*
* corresponding rows may not be marked as being non-negative.
* In parts of the context where the added equality does not hold,
* the main tableau is marked as being empty.
+ *
+ * Before we embark on the actual computation, we save a copy
+ * of the context. When we return, we check if there are any
+ * partial solutions that can potentially be merged. If so,
+ * we perform a rollback to the initial state of the context.
+ * The merging of partial solutions happens inside calls to
+ * sol_dec_level that are pushed onto the undo stack of the context.
+ * If there are no partial solutions that can potentially be merged
+ * then the rollback is skipped as it would just be wasted effort.
*/
static void find_solutions_main(struct isl_sol *sol, struct isl_tab *tab)
{
int row;
+ void *saved;
if (!tab)
goto error;
row = tab->n_redundant - 1;
}
+ saved = sol->context->op->save(sol->context);
+
find_solutions(sol, tab);
+ if (sol_has_mergeable_solutions(sol))
+ sol->context->op->restore(sol->context, saved);
+ else
+ sol->context->op->discard(saved);
+
sol->level = 0;
sol_pop(sol);
struct isl_sol_for *sol_for = NULL;
bmap = isl_basic_map_copy(bmap);
+ bmap = isl_basic_map_detect_equalities(bmap);
if (!bmap)
return -1;
- bmap = isl_basic_map_detect_equalities(bmap);
sol_for = sol_for_init(bmap, max, fn, user);
+ if (!sol_for)
+ goto error;
if (isl_basic_map_plain_is_empty(bmap))
/* nothing */;
{
int i, j;
int r;
- isl_ctx *ctx = isl_basic_set_get_ctx(bset);
+ isl_ctx *ctx;
isl_vec *v = NULL;
- isl_vec *sol = isl_vec_alloc(ctx, 0);
+ isl_vec *sol = NULL;
struct isl_tab *tab;
struct isl_trivial *triv = NULL;
int level, init;
+ if (!bset)
+ return NULL;
+
+ ctx = isl_basic_set_get_ctx(bset);
+ sol = isl_vec_alloc(ctx, 0);
+
tab = tab_for_lexmin(bset, NULL, 0, 0);
if (!tab)
goto error;
isl_ctx *ctx = isl_basic_set_get_ctx(bset);
isl_vec *sol;
+ if (!bset)
+ return NULL;
+
tab = tab_for_lexmin(bset, NULL, 0, 0);
if (!tab)
goto error;