static int qpolynomial_bound_on_domain_range(__isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *poly, struct range_data *data) { unsigned nparam = isl_basic_set_dim(bset, isl_dim_param); unsigned nvar = isl_basic_set_dim(bset, isl_dim_set); isl_set *set = NULL; if (!bset) goto error; if (nvar == 0) return add_guarded_poly(bset, poly, data); set = isl_set_from_basic_set(bset); set = isl_set_split_dims(set, isl_dim_param, 0, nparam); set = isl_set_split_dims(set, isl_dim_set, 0, nvar); data->poly = poly; data->test_monotonicity = 1; if (isl_set_foreach_basic_set(set, &basic_guarded_poly_bound, data) < 0) goto error; isl_set_free(set); isl_qpolynomial_free(poly); return 0; error: isl_set_free(set); isl_qpolynomial_free(poly); return -1; }
static isl_stat basic_guarded_poly_bound(__isl_take isl_basic_set *bset, void *user) { struct range_data *data = (struct range_data *)user; isl_ctx *ctx; unsigned nparam = isl_basic_set_dim(bset, isl_dim_param); unsigned dim = isl_basic_set_dim(bset, isl_dim_set); isl_stat r; data->signs = NULL; ctx = isl_basic_set_get_ctx(bset); data->signs = isl_alloc_array(ctx, int, isl_basic_set_dim(bset, isl_dim_all)); if (isl_basic_set_dims_get_sign(bset, isl_dim_set, 0, dim, data->signs + nparam) < 0) goto error; if (isl_basic_set_dims_get_sign(bset, isl_dim_param, 0, nparam, data->signs) < 0) goto error; r = propagate_on_domain(bset, isl_qpolynomial_copy(data->poly), data); free(data->signs); return r; error: free(data->signs); isl_basic_set_free(bset); return isl_stat_error; }
/* Given a lower and upper bound on the final variable and constraints * on the remaining variables where these bounds are active, * eliminate the variable from data->poly based on these bounds. * If the polynomial has been determined to be monotonic * in the variable, then simply plug in the appropriate bound. * If the current polynomial is tight and if this bound is integer, * then the result is still tight. In all other cases, the results * may not be tight. * Otherwise, plug in the largest bound (in absolute value) in * the positive terms (if an upper bound is wanted) or the negative terms * (if a lower bounded is wanted) and the other bound in the other terms. * * If all variables have been eliminated, then record the result. * Ohterwise, recurse on the next variable. */ static isl_stat propagate_on_bound_pair(__isl_take isl_constraint *lower, __isl_take isl_constraint *upper, __isl_take isl_basic_set *bset, void *user) { struct range_data *data = (struct range_data *)user; int save_tight = data->tight; isl_qpolynomial *poly; isl_stat r; unsigned nvar; nvar = isl_basic_set_dim(bset, isl_dim_set); if (data->monotonicity) { isl_qpolynomial *sub; isl_space *dim = isl_qpolynomial_get_domain_space(data->poly); if (data->monotonicity * data->sign > 0) { if (data->tight) data->tight = bound_is_integer(upper, nvar); sub = bound2poly(upper, dim, nvar, 1); isl_constraint_free(lower); } else { if (data->tight) data->tight = bound_is_integer(lower, nvar); sub = bound2poly(lower, dim, nvar, -1); isl_constraint_free(upper); } poly = isl_qpolynomial_copy(data->poly); poly = plug_in_at_pos(poly, nvar, sub, data); poly = isl_qpolynomial_drop_dims(poly, isl_dim_in, nvar, 1); } else { isl_qpolynomial *l, *u; isl_qpolynomial *pos, *neg; isl_space *dim = isl_qpolynomial_get_domain_space(data->poly); unsigned nparam = isl_basic_set_dim(bset, isl_dim_param); int sign = data->sign * data->signs[nparam + nvar]; data->tight = 0; u = bound2poly(upper, isl_space_copy(dim), nvar, 1); l = bound2poly(lower, dim, nvar, -1); pos = isl_qpolynomial_terms_of_sign(data->poly, data->signs, sign); neg = isl_qpolynomial_terms_of_sign(data->poly, data->signs, -sign); pos = plug_in_at_pos(pos, nvar, u, data); neg = plug_in_at_pos(neg, nvar, l, data); poly = isl_qpolynomial_add(pos, neg); poly = isl_qpolynomial_drop_dims(poly, isl_dim_in, nvar, 1); } if (isl_basic_set_dim(bset, isl_dim_set) == 0) r = add_guarded_poly(bset, poly, data); else r = propagate_on_domain(bset, poly, data); data->tight = save_tight; return r; }
/* Construct a parameter compression for "bset". * We basically just call isl_mat_parameter_compression with the right input * and then extend the resulting matrix to include the variables. * * Let the equalities be given as * * B(p) + A x = 0 * * and let [H 0] be the Hermite Normal Form of A, then * * H^-1 B(p) * * needs to be integer, so we impose that each row is divisible by * the denominator. */ __isl_give isl_morph *isl_basic_set_parameter_compression( __isl_keep isl_basic_set *bset) { unsigned nparam; unsigned nvar; int n_eq; isl_mat *H, *B; isl_vec *d; isl_mat *map, *inv; isl_basic_set *dom, *ran; if (!bset) return NULL; if (isl_basic_set_plain_is_empty(bset)) return isl_morph_empty(bset); if (bset->n_eq == 0) return isl_morph_identity(bset); isl_assert(bset->ctx, bset->n_div == 0, return NULL); n_eq = bset->n_eq; nparam = isl_basic_set_dim(bset, isl_dim_param); nvar = isl_basic_set_dim(bset, isl_dim_set); isl_assert(bset->ctx, n_eq <= nvar, return NULL); d = isl_vec_alloc(bset->ctx, n_eq); B = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, n_eq, 0, 1 + nparam); H = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, n_eq, 1 + nparam, nvar); H = isl_mat_left_hermite(H, 0, NULL, NULL); H = isl_mat_drop_cols(H, n_eq, nvar - n_eq); H = isl_mat_lin_to_aff(H); H = isl_mat_right_inverse(H); if (!H || !d) goto error; isl_seq_set(d->el, H->row[0][0], d->size); H = isl_mat_drop_rows(H, 0, 1); H = isl_mat_drop_cols(H, 0, 1); B = isl_mat_product(H, B); inv = isl_mat_parameter_compression(B, d); inv = isl_mat_diagonal(inv, isl_mat_identity(bset->ctx, nvar)); map = isl_mat_right_inverse(isl_mat_copy(inv)); dom = isl_basic_set_universe(isl_space_copy(bset->dim)); ran = isl_basic_set_universe(isl_space_copy(bset->dim)); return isl_morph_alloc(dom, ran, map, inv); error: isl_mat_free(H); isl_mat_free(B); isl_vec_free(d); return NULL; }
int cloog_constraint_set_contains_level(CloogConstraintSet *constraints, int level, int nb_parameters) { isl_basic_set *bset; bset = cloog_constraints_set_to_isl(constraints); return isl_basic_set_dim(bset, isl_dim_set) >= level; }
static __isl_give isl_mat *isl_basic_set_scan_samples( __isl_take isl_basic_set *bset) { isl_ctx *ctx; isl_size dim; struct scan_samples ss; ctx = isl_basic_set_get_ctx(bset); dim = isl_basic_set_dim(bset, isl_dim_all); if (dim < 0) goto error; ss.callback.add = scan_samples_add_sample; ss.samples = isl_mat_alloc(ctx, 0, 1 + dim); if (!ss.samples) goto error; if (isl_basic_set_scan(bset, &ss.callback) < 0) { isl_mat_free(ss.samples); return NULL; } return ss.samples; error: isl_basic_set_free(bset); return NULL; }
/* Return an isl_basic_set representation of the equality stored * at position i in the given CloogEqualities. */ static __isl_give isl_basic_set *equality_to_basic_set(CloogEqualities *equal, int i) { isl_constraint *c; isl_basic_set *bset; unsigned nparam; unsigned nvar; c = isl_constraint_copy(equal->constraints[i]); bset = isl_basic_set_from_constraint(c); nparam = isl_basic_set_dim(bset, isl_dim_param); nvar = isl_basic_set_dim(bset, isl_dim_set); bset = isl_basic_set_add(bset, isl_dim_set, equal->total_dim - (nparam + nvar)); return bset; }
unsigned isl_morph_dom_dim(__isl_keep isl_morph *morph, enum isl_dim_type type) { if (!morph) return 0; return isl_basic_set_dim(morph->dom, type); }
/* Check whether the polynomial "poly" has sign "sign" over "bset", * i.e., if sign == 1, check that the lower bound on the polynomial * is non-negative and if sign == -1, check that the upper bound on * the polynomial is non-positive. */ static int has_sign(__isl_keep isl_basic_set *bset, __isl_keep isl_qpolynomial *poly, int sign, int *signs) { struct range_data data_m; unsigned nparam; isl_space *dim; isl_val *opt; int r; enum isl_fold type; nparam = isl_basic_set_dim(bset, isl_dim_param); bset = isl_basic_set_copy(bset); poly = isl_qpolynomial_copy(poly); bset = isl_basic_set_move_dims(bset, isl_dim_set, 0, isl_dim_param, 0, nparam); poly = isl_qpolynomial_move_dims(poly, isl_dim_in, 0, isl_dim_param, 0, nparam); dim = isl_qpolynomial_get_space(poly); dim = isl_space_params(dim); dim = isl_space_from_domain(dim); dim = isl_space_add_dims(dim, isl_dim_out, 1); data_m.test_monotonicity = 0; data_m.signs = signs; data_m.sign = -sign; type = data_m.sign < 0 ? isl_fold_min : isl_fold_max; data_m.pwf = isl_pw_qpolynomial_fold_zero(dim, type); data_m.tight = 0; data_m.pwf_tight = NULL; if (propagate_on_domain(bset, poly, &data_m) < 0) goto error; if (sign > 0) opt = isl_pw_qpolynomial_fold_min(data_m.pwf); else opt = isl_pw_qpolynomial_fold_max(data_m.pwf); if (!opt) r = -1; else if (isl_val_is_nan(opt) || isl_val_is_infty(opt) || isl_val_is_neginfty(opt)) r = 0; else r = sign * isl_val_sgn(opt) >= 0; isl_val_free(opt); return r; error: isl_pw_qpolynomial_fold_free(data_m.pwf); return -1; }
/* Project range of morph onto its parameter domain. */ __isl_give isl_morph *isl_morph_ran_params(__isl_take isl_morph *morph) { unsigned n; if (!morph) return NULL; n = isl_basic_set_dim(morph->ran, isl_dim_set); morph = isl_morph_remove_ran_dims(morph, isl_dim_set, 0, n); if (!morph) return NULL; morph->ran = isl_basic_set_params(morph->ran); if (morph->ran) return morph; isl_morph_free(morph); return NULL; }
/* Recursively perform range propagation on the polynomial "poly" * defined over the basic set "bset" and collect the results in "data". */ static isl_stat propagate_on_domain(__isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *poly, struct range_data *data) { isl_ctx *ctx; isl_qpolynomial *save_poly = data->poly; int save_monotonicity = data->monotonicity; unsigned d; if (!bset || !poly) goto error; ctx = isl_basic_set_get_ctx(bset); d = isl_basic_set_dim(bset, isl_dim_set); isl_assert(ctx, d >= 1, goto error); if (isl_qpolynomial_is_cst(poly, NULL, NULL)) { bset = isl_basic_set_project_out(bset, isl_dim_set, 0, d); poly = isl_qpolynomial_drop_dims(poly, isl_dim_in, 0, d); return add_guarded_poly(bset, poly, data); } if (data->test_monotonicity) data->monotonicity = monotonicity(bset, poly, data); else data->monotonicity = 0; if (data->monotonicity < -1) goto error; data->poly = poly; if (isl_basic_set_foreach_bound_pair(bset, isl_dim_set, d - 1, &propagate_on_bound_pair, data) < 0) goto error; isl_basic_set_free(bset); isl_qpolynomial_free(poly); data->monotonicity = save_monotonicity; data->poly = save_poly; return isl_stat_ok; error: isl_basic_set_free(bset); isl_qpolynomial_free(poly); data->monotonicity = save_monotonicity; data->poly = save_poly; return isl_stat_error; }
/* Return 1 if poly is monotonically increasing in the last set variable, * -1 if poly is monotonically decreasing in the last set variable, * 0 if no conclusion, * -2 on error. * * We simply check the sign of p(x+1)-p(x) */ static int monotonicity(__isl_keep isl_basic_set *bset, __isl_keep isl_qpolynomial *poly, struct range_data *data) { isl_ctx *ctx; isl_space *dim; isl_qpolynomial *sub = NULL; isl_qpolynomial *diff = NULL; int result = 0; int s; unsigned nvar; ctx = isl_qpolynomial_get_ctx(poly); dim = isl_qpolynomial_get_domain_space(poly); nvar = isl_basic_set_dim(bset, isl_dim_set); sub = isl_qpolynomial_var_on_domain(isl_space_copy(dim), isl_dim_set, nvar - 1); sub = isl_qpolynomial_add(sub, isl_qpolynomial_rat_cst_on_domain(dim, ctx->one, ctx->one)); diff = isl_qpolynomial_substitute(isl_qpolynomial_copy(poly), isl_dim_in, nvar - 1, 1, &sub); diff = isl_qpolynomial_sub(diff, isl_qpolynomial_copy(poly)); s = has_sign(bset, diff, 1, data->signs); if (s < 0) goto error; if (s) result = 1; else { s = has_sign(bset, diff, -1, data->signs); if (s < 0) goto error; if (s) result = -1; } isl_qpolynomial_free(diff); isl_qpolynomial_free(sub); return result; error: isl_qpolynomial_free(diff); isl_qpolynomial_free(sub); return -2; }
static struct cloog_isl_dim basic_set_cloog_dim_to_isl_dim( __isl_keep isl_basic_set *bset, int pos) { enum isl_dim_type types[] = { isl_dim_set, isl_dim_div, isl_dim_param }; int i; struct cloog_isl_dim ci_dim; for (i = 0; i < 3; ++i) { unsigned dim = isl_basic_set_dim(bset, types[i]); if (pos < dim) { ci_dim.type = types[i]; ci_dim.pos = pos; return ci_dim; } pos -= dim; } assert(0); }
/* Update "enforced" such that it only involves constraints that are * also enforced by "graft". */ static __isl_give isl_basic_set *update_enforced( __isl_take isl_basic_set *enforced, __isl_keep isl_ast_graft *graft, int depth) { isl_basic_set *enforced_g; enforced_g = isl_ast_graft_get_enforced(graft); if (depth < isl_basic_set_dim(enforced_g, isl_dim_set)) enforced_g = isl_basic_set_eliminate(enforced_g, isl_dim_set, depth, 1); enforced_g = isl_basic_set_remove_unknown_divs(enforced_g); enforced_g = isl_basic_set_align_params(enforced_g, isl_basic_set_get_space(enforced)); enforced = isl_basic_set_align_params(enforced, isl_basic_set_get_space(enforced_g)); enforced = isl_set_simple_hull(isl_basic_set_union(enforced, enforced_g)); return enforced; }
int cloog_constraint_set_n_iterators(CloogConstraintSet *constraints, int n_par) { isl_basic_set *bset; bset = cloog_constraints_set_to_isl(constraints); return isl_basic_set_dim(bset, isl_dim_set); }
/* Given a basic set, exploit the equalties in the a basic set to construct * a morphishm that maps the basic set to a lower-dimensional space. * Specifically, the morphism reduces the number of dimensions of type "type". * * This function is a slight generalization of isl_mat_variable_compression * in that it allows the input to be parametric and that it allows for the * compression of either parameters or set variables. * * We first select the equalities of interest, that is those that involve * variables of type "type" and no later variables. * Denote those equalities as * * -C(p) + M x = 0 * * where C(p) depends on the parameters if type == isl_dim_set and * is a constant if type == isl_dim_param. * * First compute the (left) Hermite normal form of M, * * M [U1 U2] = M U = H = [H1 0] * or * M = H Q = [H1 0] [Q1] * [Q2] * * with U, Q unimodular, Q = U^{-1} (and H lower triangular). * Define the transformed variables as * * x = [U1 U2] [ x1' ] = [U1 U2] [Q1] x * [ x2' ] [Q2] * * The equalities then become * * -C(p) + H1 x1' = 0 or x1' = H1^{-1} C(p) = C'(p) * * If the denominator of the constant term does not divide the * the common denominator of the parametric terms, then every * integer point is mapped to a non-integer point and then the original set has no * integer solutions (since the x' are a unimodular transformation * of the x). In this case, an empty morphism is returned. * Otherwise, the transformation is given by * * x = U1 H1^{-1} C(p) + U2 x2' * * The inverse transformation is simply * * x2' = Q2 x * * Both matrices are extended to map the full original space to the full * compressed space. */ __isl_give isl_morph *isl_basic_set_variable_compression( __isl_keep isl_basic_set *bset, enum isl_dim_type type) { unsigned otype; unsigned ntype; unsigned orest; unsigned nrest; int f_eq, n_eq; isl_space *dim; isl_mat *H, *U, *Q, *C = NULL, *H1, *U1, *U2; isl_basic_set *dom, *ran; if (!bset) return NULL; if (isl_basic_set_plain_is_empty(bset)) return isl_morph_empty(bset); isl_assert(bset->ctx, bset->n_div == 0, return NULL); otype = 1 + isl_space_offset(bset->dim, type); ntype = isl_basic_set_dim(bset, type); orest = otype + ntype; nrest = isl_basic_set_total_dim(bset) - (orest - 1); for (f_eq = 0; f_eq < bset->n_eq; ++f_eq) if (isl_seq_first_non_zero(bset->eq[f_eq] + orest, nrest) == -1) break; for (n_eq = 0; f_eq + n_eq < bset->n_eq; ++n_eq) if (isl_seq_first_non_zero(bset->eq[f_eq + n_eq] + otype, ntype) == -1) break; if (n_eq == 0) return isl_morph_identity(bset); H = isl_mat_sub_alloc6(bset->ctx, bset->eq, f_eq, n_eq, otype, ntype); H = isl_mat_left_hermite(H, 0, &U, &Q); if (!H || !U || !Q) goto error; Q = isl_mat_drop_rows(Q, 0, n_eq); Q = isl_mat_diagonal(isl_mat_identity(bset->ctx, otype), Q); Q = isl_mat_diagonal(Q, isl_mat_identity(bset->ctx, nrest)); C = isl_mat_alloc(bset->ctx, 1 + n_eq, otype); if (!C) goto error; isl_int_set_si(C->row[0][0], 1); isl_seq_clr(C->row[0] + 1, otype - 1); isl_mat_sub_neg(C->ctx, C->row + 1, bset->eq + f_eq, n_eq, 0, 0, otype); H1 = isl_mat_sub_alloc(H, 0, H->n_row, 0, H->n_row); H1 = isl_mat_lin_to_aff(H1); C = isl_mat_inverse_product(H1, C); if (!C) goto error; isl_mat_free(H); if (!isl_int_is_one(C->row[0][0])) { int i; isl_int g; isl_int_init(g); for (i = 0; i < n_eq; ++i) { isl_seq_gcd(C->row[1 + i] + 1, otype - 1, &g); isl_int_gcd(g, g, C->row[0][0]); if (!isl_int_is_divisible_by(C->row[1 + i][0], g)) break; } isl_int_clear(g); if (i < n_eq) { isl_mat_free(C); isl_mat_free(U); isl_mat_free(Q); return isl_morph_empty(bset); } C = isl_mat_normalize(C); } U1 = isl_mat_sub_alloc(U, 0, U->n_row, 0, n_eq); U1 = isl_mat_lin_to_aff(U1); U2 = isl_mat_sub_alloc(U, 0, U->n_row, n_eq, U->n_row - n_eq); U2 = isl_mat_lin_to_aff(U2); isl_mat_free(U); C = isl_mat_product(U1, C); C = isl_mat_aff_direct_sum(C, U2); C = insert_parameter_rows(C, otype - 1); C = isl_mat_diagonal(C, isl_mat_identity(bset->ctx, nrest)); dim = isl_space_copy(bset->dim); dim = isl_space_drop_dims(dim, type, 0, ntype); dim = isl_space_add_dims(dim, type, ntype - n_eq); ran = isl_basic_set_universe(dim); dom = copy_equalities(bset, f_eq, n_eq); return isl_morph_alloc(dom, ran, Q, C); error: isl_mat_free(C); isl_mat_free(H); isl_mat_free(U); isl_mat_free(Q); return NULL; }
/** * Reduce the modulo guard expressed by "constraints" using equalities * found in outer nesting levels (stored in "equal"). * The modulo guard may be an equality or a pair of inequalities. * In case of a pair of inequalities, *bound contains the bound on the * corresponding modulo expression. If any reduction is performed * then this bound is recomputed. * * "level" may not correspond to an existentially quantified variable. * * We first check if there are any equalities we can use. If not, * there is again nothing to reduce. * For the actual reduction, we use isl_basic_set_gist, but this * function will only perform the reduction we want here if the * the variable that imposes the modulo constraint has been projected * out (i.e., turned into an existentially quantified variable). * After the call to isl_basic_set_gist, we need to move the * existential variable back into the position where the calling * function expects it (assuming there are any constraints left). * We do this by adding an equality between the given dimension and * the existentially quantified variable. * * If there are no existentially quantified variables left, then * we don't need to add this equality. * If, on the other hand, the resulting basic set involves more * than one existentially quantified variable, then the caller * will not be able to handle the result, so we just return the * original input instead. */ CloogConstraintSet *cloog_constraint_set_reduce(CloogConstraintSet *constraints, int level, CloogEqualities *equal, int nb_par, cloog_int_t *bound) { int j; isl_space *idim; struct isl_basic_set *eq; struct isl_basic_map *id; struct cloog_isl_dim dim; struct isl_constraint *c; unsigned constraints_dim; unsigned n_div; isl_basic_set *bset, *orig; bset = cloog_constraints_set_to_isl(constraints); orig = isl_basic_set_copy(bset); dim = set_cloog_dim_to_isl_dim(constraints, level - 1); assert(dim.type == isl_dim_set); eq = NULL; for (j = 0; j < level - 1; ++j) { isl_basic_set *bset_j; if (equal->types[j] != EQTYPE_EXAFFINE) continue; bset_j = equality_to_basic_set(equal, j); if (!eq) eq = bset_j; else eq = isl_basic_set_intersect(eq, bset_j); } if (!eq) { isl_basic_set_free(orig); return cloog_constraint_set_from_isl_basic_set(bset); } idim = isl_space_map_from_set(isl_basic_set_get_space(bset)); id = isl_basic_map_identity(idim); id = isl_basic_map_remove_dims(id, isl_dim_out, dim.pos, 1); bset = isl_basic_set_apply(bset, isl_basic_map_copy(id)); bset = isl_basic_set_apply(bset, isl_basic_map_reverse(id)); constraints_dim = isl_basic_set_dim(bset, isl_dim_set); eq = isl_basic_set_remove_dims(eq, isl_dim_set, constraints_dim, isl_basic_set_dim(eq, isl_dim_set) - constraints_dim); bset = isl_basic_set_gist(bset, eq); n_div = isl_basic_set_dim(bset, isl_dim_div); if (n_div > 1) { isl_basic_set_free(bset); return cloog_constraint_set_from_isl_basic_set(orig); } if (n_div < 1) { isl_basic_set_free(orig); return cloog_constraint_set_from_isl_basic_set(bset); } c = isl_equality_alloc(isl_basic_set_get_local_space(bset)); c = isl_constraint_set_coefficient_si(c, isl_dim_div, 0, 1); c = isl_constraint_set_coefficient_si(c, isl_dim_set, dim.pos, -1); bset = isl_basic_set_add_constraint(bset, c); isl_int_set_si(*bound, 0); constraints = cloog_constraint_set_from_isl_basic_set(bset); cloog_constraint_set_foreach_constraint(constraints, add_constant_term, bound); isl_basic_set_free(orig); return cloog_constraint_set_from_isl_basic_set(bset); }