+ isl_int_init(min);
+ isl_int_init(max);
+ total = isl_space_dim(qp->dim, isl_dim_all);
+ for (i = 0; i < qp->div->n_row; ++i) {
+ enum isl_lp_result lp_res;
+
+ if (isl_seq_first_non_zero(qp->div->row[i] + 2 + total,
+ qp->div->n_row) != -1)
+ continue;
+
+ lp_res = isl_set_solve_lp(set, 0, qp->div->row[i] + 1,
+ set->ctx->one, &min, NULL, NULL);
+ if (lp_res == isl_lp_error)
+ goto error2;
+ if (lp_res == isl_lp_unbounded || lp_res == isl_lp_empty)
+ continue;
+ isl_int_fdiv_q(min, min, qp->div->row[i][0]);
+
+ lp_res = isl_set_solve_lp(set, 1, qp->div->row[i] + 1,
+ set->ctx->one, &max, NULL, NULL);
+ if (lp_res == isl_lp_error)
+ goto error2;
+ if (lp_res == isl_lp_unbounded || lp_res == isl_lp_empty)
+ continue;
+ isl_int_fdiv_q(max, max, qp->div->row[i][0]);
+
+ isl_int_sub(max, max, min);
+ if (isl_int_cmp_si(max, data->max_periods) < 0) {
+ isl_int_add(max, max, min);
+ break;
+ }
+ }
+
+ if (i < qp->div->n_row) {
+ r = split_div(set, qp, i, min, max, data);
+ } else {
+ pwqp = isl_pw_qpolynomial_alloc(set, qp);
+ data->res = isl_pw_qpolynomial_add_disjoint(data->res, pwqp);
+ }
+
+ isl_int_clear(max);
+ isl_int_clear(min);
+
+ return r;
+error2:
+ isl_int_clear(max);
+ isl_int_clear(min);
+error:
+ isl_set_free(set);
+ isl_qpolynomial_free(qp);
+ return -1;
+}
+
+/* If any quasi-polynomial in pwqp refers to any integer division
+ * that can only attain "max_periods" distinct values on its domain
+ * then split the domain along those distinct values.
+ */
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_split_periods(
+ __isl_take isl_pw_qpolynomial *pwqp, int max_periods)
+{
+ struct isl_split_periods_data data;
+
+ data.max_periods = max_periods;
+ data.res = isl_pw_qpolynomial_zero(isl_pw_qpolynomial_get_space(pwqp));
+
+ if (isl_pw_qpolynomial_foreach_piece(pwqp, &split_periods, &data) < 0)
+ goto error;
+
+ isl_pw_qpolynomial_free(pwqp);
+
+ return data.res;
+error:
+ isl_pw_qpolynomial_free(data.res);
+ isl_pw_qpolynomial_free(pwqp);
+ return NULL;
+}
+
+/* Construct a piecewise quasipolynomial that is constant on the given
+ * domain. In particular, it is
+ * 0 if cst == 0
+ * 1 if cst == 1
+ * infinity if cst == -1
+ */
+static __isl_give isl_pw_qpolynomial *constant_on_domain(
+ __isl_take isl_basic_set *bset, int cst)
+{
+ isl_space *dim;
+ isl_qpolynomial *qp;
+
+ if (!bset)
+ return NULL;
+
+ bset = isl_basic_set_params(bset);
+ dim = isl_basic_set_get_space(bset);
+ if (cst < 0)
+ qp = isl_qpolynomial_infty_on_domain(dim);
+ else if (cst == 0)
+ qp = isl_qpolynomial_zero_on_domain(dim);
+ else
+ qp = isl_qpolynomial_one_on_domain(dim);
+ return isl_pw_qpolynomial_alloc(isl_set_from_basic_set(bset), qp);
+}
+
+/* Factor bset, call fn on each of the factors and return the product.
+ *
+ * If no factors can be found, simply call fn on the input.
+ * Otherwise, construct the factors based on the factorizer,
+ * call fn on each factor and compute the product.
+ */
+static __isl_give isl_pw_qpolynomial *compressed_multiplicative_call(
+ __isl_take isl_basic_set *bset,
+ __isl_give isl_pw_qpolynomial *(*fn)(__isl_take isl_basic_set *bset))
+{
+ int i, n;
+ isl_space *dim;
+ isl_set *set;
+ isl_factorizer *f;
+ isl_qpolynomial *qp;
+ isl_pw_qpolynomial *pwqp;
+ unsigned nparam;
+ unsigned nvar;
+
+ f = isl_basic_set_factorizer(bset);
+ if (!f)
+ goto error;
+ if (f->n_group == 0) {
+ isl_factorizer_free(f);
+ return fn(bset);
+ }
+
+ nparam = isl_basic_set_dim(bset, isl_dim_param);
+ nvar = isl_basic_set_dim(bset, isl_dim_set);
+
+ dim = isl_basic_set_get_space(bset);
+ dim = isl_space_domain(dim);
+ set = isl_set_universe(isl_space_copy(dim));
+ qp = isl_qpolynomial_one_on_domain(dim);
+ pwqp = isl_pw_qpolynomial_alloc(set, qp);
+
+ bset = isl_morph_basic_set(isl_morph_copy(f->morph), bset);
+
+ for (i = 0, n = 0; i < f->n_group; ++i) {
+ isl_basic_set *bset_i;
+ isl_pw_qpolynomial *pwqp_i;
+
+ bset_i = isl_basic_set_copy(bset);
+ bset_i = isl_basic_set_drop_constraints_involving(bset_i,
+ nparam + n + f->len[i], nvar - n - f->len[i]);
+ bset_i = isl_basic_set_drop_constraints_involving(bset_i,
+ nparam, n);
+ bset_i = isl_basic_set_drop(bset_i, isl_dim_set,
+ n + f->len[i], nvar - n - f->len[i]);
+ bset_i = isl_basic_set_drop(bset_i, isl_dim_set, 0, n);
+
+ pwqp_i = fn(bset_i);
+ pwqp = isl_pw_qpolynomial_mul(pwqp, pwqp_i);
+
+ n += f->len[i];
+ }
+
+ isl_basic_set_free(bset);
+ isl_factorizer_free(f);
+
+ return pwqp;
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+/* Factor bset, call fn on each of the factors and return the product.
+ * The function is assumed to evaluate to zero on empty domains,
+ * to one on zero-dimensional domains and to infinity on unbounded domains
+ * and will not be called explicitly on zero-dimensional or unbounded domains.
+ *
+ * We first check for some special cases and remove all equalities.
+ * Then we hand over control to compressed_multiplicative_call.
+ */
+__isl_give isl_pw_qpolynomial *isl_basic_set_multiplicative_call(
+ __isl_take isl_basic_set *bset,
+ __isl_give isl_pw_qpolynomial *(*fn)(__isl_take isl_basic_set *bset))
+{
+ int bounded;
+ isl_morph *morph;
+ isl_pw_qpolynomial *pwqp;
+
+ if (!bset)
+ return NULL;
+
+ if (isl_basic_set_plain_is_empty(bset))
+ return constant_on_domain(bset, 0);
+
+ if (isl_basic_set_dim(bset, isl_dim_set) == 0)
+ return constant_on_domain(bset, 1);
+
+ bounded = isl_basic_set_is_bounded(bset);
+ if (bounded < 0)
+ goto error;
+ if (!bounded)
+ return constant_on_domain(bset, -1);
+
+ if (bset->n_eq == 0)
+ return compressed_multiplicative_call(bset, fn);
+
+ morph = isl_basic_set_full_compression(bset);
+ bset = isl_morph_basic_set(isl_morph_copy(morph), bset);
+
+ pwqp = compressed_multiplicative_call(bset, fn);
+
+ morph = isl_morph_dom_params(morph);
+ morph = isl_morph_ran_params(morph);
+ morph = isl_morph_inverse(morph);
+
+ pwqp = isl_pw_qpolynomial_morph_domain(pwqp, morph);
+
+ return pwqp;
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+/* Drop all floors in "qp", turning each integer division [a/m] into
+ * a rational division a/m. If "down" is set, then the integer division
+ * is replaces by (a-(m-1))/m instead.
+ */
+static __isl_give isl_qpolynomial *qp_drop_floors(
+ __isl_take isl_qpolynomial *qp, int down)
+{
+ int i;
+ struct isl_upoly *s;
+
+ if (!qp)
+ return NULL;
+ if (qp->div->n_row == 0)
+ return qp;
+
+ qp = isl_qpolynomial_cow(qp);
+ if (!qp)
+ return NULL;
+
+ for (i = qp->div->n_row - 1; i >= 0; --i) {
+ if (down) {
+ isl_int_sub(qp->div->row[i][1],
+ qp->div->row[i][1], qp->div->row[i][0]);
+ isl_int_add_ui(qp->div->row[i][1],
+ qp->div->row[i][1], 1);
+ }
+ s = isl_upoly_from_affine(qp->dim->ctx, qp->div->row[i] + 1,
+ qp->div->row[i][0], qp->div->n_col - 1);
+ qp = substitute_div(qp, i, s);
+ if (!qp)
+ return NULL;
+ }
+
+ return qp;
+}
+
+/* Drop all floors in "pwqp", turning each integer division [a/m] into
+ * a rational division a/m.
+ */
+static __isl_give isl_pw_qpolynomial *pwqp_drop_floors(
+ __isl_take isl_pw_qpolynomial *pwqp)
+{
+ int i;
+
+ if (!pwqp)
+ return NULL;
+
+ if (isl_pw_qpolynomial_is_zero(pwqp))
+ return pwqp;
+
+ pwqp = isl_pw_qpolynomial_cow(pwqp);
+ if (!pwqp)
+ return NULL;
+
+ for (i = 0; i < pwqp->n; ++i) {
+ pwqp->p[i].qp = qp_drop_floors(pwqp->p[i].qp, 0);
+ if (!pwqp->p[i].qp)
+ goto error;
+ }
+
+ return pwqp;
+error:
+ isl_pw_qpolynomial_free(pwqp);
+ return NULL;
+}
+
+/* Adjust all the integer divisions in "qp" such that they are at least
+ * one over the given orthant (identified by "signs"). This ensures
+ * that they will still be non-negative even after subtracting (m-1)/m.
+ *
+ * In particular, f is replaced by f' + v, changing f = [a/m]
+ * to f' = [(a - m v)/m].
+ * If the constant term k in a is smaller than m,
+ * the constant term of v is set to floor(k/m) - 1.
+ * For any other term, if the coefficient c and the variable x have
+ * the same sign, then no changes are needed.
+ * Otherwise, if the variable is positive (and c is negative),
+ * then the coefficient of x in v is set to floor(c/m).
+ * If the variable is negative (and c is positive),
+ * then the coefficient of x in v is set to ceil(c/m).
+ */
+static __isl_give isl_qpolynomial *make_divs_pos(__isl_take isl_qpolynomial *qp,
+ int *signs)
+{
+ int i, j;
+ int total;
+ isl_vec *v = NULL;
+ struct isl_upoly *s;
+
+ qp = isl_qpolynomial_cow(qp);
+ if (!qp)
+ return NULL;
+ qp->div = isl_mat_cow(qp->div);
+ if (!qp->div)
+ goto error;
+
+ total = isl_space_dim(qp->dim, isl_dim_all);
+ v = isl_vec_alloc(qp->div->ctx, qp->div->n_col - 1);
+
+ for (i = 0; i < qp->div->n_row; ++i) {
+ isl_int *row = qp->div->row[i];
+ v = isl_vec_clr(v);
+ if (!v)
+ goto error;
+ if (isl_int_lt(row[1], row[0])) {
+ isl_int_fdiv_q(v->el[0], row[1], row[0]);
+ isl_int_sub_ui(v->el[0], v->el[0], 1);
+ isl_int_submul(row[1], row[0], v->el[0]);
+ }
+ for (j = 0; j < total; ++j) {
+ if (isl_int_sgn(row[2 + j]) * signs[j] >= 0)
+ continue;
+ if (signs[j] < 0)
+ isl_int_cdiv_q(v->el[1 + j], row[2 + j], row[0]);
+ else
+ isl_int_fdiv_q(v->el[1 + j], row[2 + j], row[0]);
+ isl_int_submul(row[2 + j], row[0], v->el[1 + j]);
+ }
+ for (j = 0; j < i; ++j) {
+ if (isl_int_sgn(row[2 + total + j]) >= 0)
+ continue;
+ isl_int_fdiv_q(v->el[1 + total + j],
+ row[2 + total + j], row[0]);
+ isl_int_submul(row[2 + total + j],
+ row[0], v->el[1 + total + j]);
+ }
+ for (j = i + 1; j < qp->div->n_row; ++j) {
+ if (isl_int_is_zero(qp->div->row[j][2 + total + i]))
+ continue;
+ isl_seq_combine(qp->div->row[j] + 1,
+ qp->div->ctx->one, qp->div->row[j] + 1,
+ qp->div->row[j][2 + total + i], v->el, v->size);
+ }
+ isl_int_set_si(v->el[1 + total + i], 1);
+ s = isl_upoly_from_affine(qp->dim->ctx, v->el,
+ qp->div->ctx->one, v->size);
+ qp->upoly = isl_upoly_subs(qp->upoly, total + i, 1, &s);
+ isl_upoly_free(s);
+ if (!qp->upoly)
+ goto error;
+ }
+
+ isl_vec_free(v);
+ return qp;
+error:
+ isl_vec_free(v);
+ isl_qpolynomial_free(qp);
+ return NULL;
+}
+
+struct isl_to_poly_data {
+ int sign;
+ isl_pw_qpolynomial *res;
+ isl_qpolynomial *qp;
+};
+
+/* Appoximate data->qp by a polynomial on the orthant identified by "signs".
+ * We first make all integer divisions positive and then split the
+ * quasipolynomials into terms with sign data->sign (the direction
+ * of the requested approximation) and terms with the opposite sign.
+ * In the first set of terms, each integer division [a/m] is
+ * overapproximated by a/m, while in the second it is underapproximated
+ * by (a-(m-1))/m.
+ */
+static int to_polynomial_on_orthant(__isl_take isl_set *orthant, int *signs,
+ void *user)
+{
+ struct isl_to_poly_data *data = user;
+ isl_pw_qpolynomial *t;
+ isl_qpolynomial *qp, *up, *down;
+
+ qp = isl_qpolynomial_copy(data->qp);
+ qp = make_divs_pos(qp, signs);
+
+ up = isl_qpolynomial_terms_of_sign(qp, signs, data->sign);
+ up = qp_drop_floors(up, 0);
+ down = isl_qpolynomial_terms_of_sign(qp, signs, -data->sign);
+ down = qp_drop_floors(down, 1);
+
+ isl_qpolynomial_free(qp);
+ qp = isl_qpolynomial_add(up, down);
+
+ t = isl_pw_qpolynomial_alloc(orthant, qp);
+ data->res = isl_pw_qpolynomial_add_disjoint(data->res, t);