/* Look for all equalities satisfied by the integer points in bset, * which is assumed not to have any explicit equalities. * * The equalities are obtained by successively looking for * a point that is affinely independent of the points found so far. * In particular, for each equality satisfied by the points so far, * we check if there is any point on a hyperplane parallel to the * corresponding hyperplane shifted by at least one (in either direction). * * Before looking for any outside points, we first compute the recession * cone. The directions of this recession cone will always be part * of the affine hull, so there is no need for looking for any points * in these directions. * In particular, if the recession cone is full-dimensional, then * the affine hull is simply the whole universe. */ static struct isl_basic_set *uset_affine_hull(struct isl_basic_set *bset) { struct isl_basic_set *cone; if (isl_basic_set_plain_is_empty(bset)) return bset; cone = isl_basic_set_recession_cone(isl_basic_set_copy(bset)); if (!cone) goto error; if (cone->n_eq == 0) { struct isl_basic_set *hull; isl_basic_set_free(cone); hull = isl_basic_set_universe_like(bset); isl_basic_set_free(bset); return hull; } if (cone->n_eq < isl_basic_set_total_dim(cone)) return affine_hull_with_cone(bset, cone); isl_basic_set_free(cone); return uset_affine_hull_bounded(bset); error: isl_basic_set_free(bset); return NULL; }
static struct isl_vec *interval_sample(struct isl_basic_set *bset) { int i; isl_int t; struct isl_vec *sample; bset = isl_basic_set_simplify(bset); if (!bset) return NULL; if (isl_basic_set_plain_is_empty(bset)) return empty_sample(bset); if (bset->n_eq == 0 && bset->n_ineq == 0) return zero_sample(bset); sample = isl_vec_alloc(bset->ctx, 2); if (!sample) goto error; if (!bset) return NULL; isl_int_set_si(sample->block.data[0], 1); if (bset->n_eq > 0) { isl_assert(bset->ctx, bset->n_eq == 1, goto error); isl_assert(bset->ctx, bset->n_ineq == 0, goto error); if (isl_int_is_one(bset->eq[0][1])) isl_int_neg(sample->el[1], bset->eq[0][0]); else { isl_assert(bset->ctx, isl_int_is_negone(bset->eq[0][1]), goto error); isl_int_set(sample->el[1], bset->eq[0][0]); } isl_basic_set_free(bset); return sample; }
/* 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; }
/* 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; }
/* Look for all equalities satisfied by the integer points in bset, * which is assumed to be bounded. * * The equalities are obtained by successively looking for * a point that is affinely independent of the points found so far. * In particular, for each equality satisfied by the points so far, * we check if there is any point on a hyperplane parallel to the * corresponding hyperplane shifted by at least one (in either direction). */ static struct isl_basic_set *uset_affine_hull_bounded(struct isl_basic_set *bset) { struct isl_vec *sample = NULL; struct isl_basic_set *hull; struct isl_tab *tab = NULL; unsigned dim; if (isl_basic_set_plain_is_empty(bset)) return bset; dim = isl_basic_set_n_dim(bset); if (bset->sample && bset->sample->size == 1 + dim) { int contains = isl_basic_set_contains(bset, bset->sample); if (contains < 0) goto error; if (contains) { if (dim == 0) return bset; sample = isl_vec_copy(bset->sample); } else { isl_vec_free(bset->sample); bset->sample = NULL; } } tab = isl_tab_from_basic_set(bset); if (!tab) goto error; if (tab->empty) { isl_tab_free(tab); isl_vec_free(sample); return isl_basic_set_set_to_empty(bset); } if (isl_tab_track_bset(tab, isl_basic_set_copy(bset)) < 0) goto error; if (!sample) { struct isl_tab_undo *snap; snap = isl_tab_snap(tab); sample = isl_tab_sample(tab); if (isl_tab_rollback(tab, snap) < 0) goto error; isl_vec_free(tab->bmap->sample); tab->bmap->sample = isl_vec_copy(sample); } if (!sample) goto error; if (sample->size == 0) { isl_tab_free(tab); isl_vec_free(sample); return isl_basic_set_set_to_empty(bset); } hull = isl_basic_set_from_vec(sample); isl_basic_set_free(bset); hull = extend_affine_hull(tab, hull); isl_tab_free(tab); return hull; error: isl_vec_free(sample); isl_tab_free(tab); isl_basic_set_free(bset); return NULL; }