*/
#include <stdlib.h>
+#include <isl_factorization.h>
#include <isl_lp.h>
#include <isl_seq.h>
#include <isl_union_map_private.h>
#include <isl_point_private.h>
#include <isl_dim_private.h>
#include <isl_map_private.h>
+#include <isl_mat_private.h>
static unsigned pos(__isl_keep isl_dim *dim, enum isl_dim_type type)
{
return &cst->up;
}
+__isl_give struct isl_upoly *isl_upoly_one(struct isl_ctx *ctx)
+{
+ struct isl_upoly_cst *cst;
+
+ cst = isl_upoly_cst_alloc(ctx);
+ if (!cst)
+ return NULL;
+
+ isl_int_set_si(cst->n, 1);
+ isl_int_set_si(cst->d, 1);
+
+ return &cst->up;
+}
+
__isl_give struct isl_upoly *isl_upoly_infty(struct isl_ctx *ctx)
{
struct isl_upoly_cst *cst;
return isl_qpolynomial_alloc(dim, 0, isl_upoly_zero(dim->ctx));
}
+__isl_give isl_qpolynomial *isl_qpolynomial_one(__isl_take isl_dim *dim)
+{
+ return isl_qpolynomial_alloc(dim, 0, isl_upoly_one(dim->ctx));
+}
+
__isl_give isl_qpolynomial *isl_qpolynomial_infty(__isl_take isl_dim *dim)
{
return isl_qpolynomial_alloc(dim, 0, isl_upoly_infty(dim->ctx));
struct isl_qpolynomial *qp = NULL;
struct isl_upoly_rec *rec;
struct isl_upoly_cst *cst;
- int i;
+ int i, d;
int pos;
if (!div)
return NULL;
- isl_assert(div->ctx, div->bmap->n_div == 1, goto error);
- pos = isl_dim_total(div->bmap->dim);
+ d = div->line - div->bmap->div;
+
+ pos = isl_dim_total(div->bmap->dim) + d;
rec = isl_upoly_alloc_rec(div->ctx, pos, 1 + power);
- qp = isl_qpolynomial_alloc(isl_basic_map_get_dim(div->bmap), 1,
- &rec->up);
+ qp = isl_qpolynomial_alloc(isl_basic_map_get_dim(div->bmap),
+ div->bmap->n_div, &rec->up);
if (!qp)
goto error;
- isl_seq_cpy(qp->div->row[0], div->line[0], qp->div->n_col - 1);
- isl_int_set_si(qp->div->row[0][qp->div->n_col - 1], 0);
+ for (i = 0; i < div->bmap->n_div; ++i)
+ isl_seq_cpy(qp->div->row[i], div->bmap->div[i], qp->div->n_col);
for (i = 0; i < 1 + power; ++i) {
rec->p[i] = isl_upoly_zero(div->ctx);
return NULL;
}
+__isl_give isl_qpolynomial *isl_qpolynomial_set_dim_name(
+ __isl_take isl_qpolynomial *qp,
+ enum isl_dim_type type, unsigned pos, const char *s)
+{
+ qp = isl_qpolynomial_cow(qp);
+ if (!qp)
+ return NULL;
+ qp->dim = isl_dim_set_name(qp->dim, type, pos, s);
+ if (!qp->dim)
+ goto error;
+ return qp;
+error:
+ isl_qpolynomial_free(qp);
+ return NULL;
+}
+
__isl_give isl_qpolynomial *isl_qpolynomial_drop_dims(
__isl_take isl_qpolynomial *qp,
enum isl_dim_type type, unsigned first, unsigned n)
return up;
}
+/* Remove common factor of non-constant terms and denominator.
+ */
+static void normalize_div(__isl_keep isl_qpolynomial *qp, int div)
+{
+ isl_ctx *ctx = qp->div->ctx;
+ unsigned total = qp->div->n_col - 2;
+
+ isl_seq_gcd(qp->div->row[div] + 2, total, &ctx->normalize_gcd);
+ isl_int_gcd(ctx->normalize_gcd,
+ ctx->normalize_gcd, qp->div->row[div][0]);
+ if (isl_int_is_one(ctx->normalize_gcd))
+ return;
+
+ isl_seq_scale_down(qp->div->row[div] + 2, qp->div->row[div] + 2,
+ ctx->normalize_gcd, total);
+ isl_int_divexact(qp->div->row[div][0], qp->div->row[div][0],
+ ctx->normalize_gcd);
+ isl_int_fdiv_q(qp->div->row[div][1], qp->div->row[div][1],
+ ctx->normalize_gcd);
+}
+
+/* Replace the integer division identified by "div" by the polynomial "s".
+ * The integer division is assumed not to appear in the definition
+ * of any other integer divisions.
+ */
+static __isl_give isl_qpolynomial *substitute_div(
+ __isl_take isl_qpolynomial *qp,
+ int div, __isl_take struct isl_upoly *s)
+{
+ int i;
+ int total;
+ int *reordering;
+
+ if (!qp || !s)
+ goto error;
+
+ qp = isl_qpolynomial_cow(qp);
+ if (!qp)
+ goto error;
+
+ total = isl_dim_total(qp->dim);
+ qp->upoly = isl_upoly_subs(qp->upoly, total + div, 1, &s);
+ if (!qp->upoly)
+ goto error;
+
+ reordering = isl_alloc_array(qp->dim->ctx, int, total + qp->div->n_row);
+ if (!reordering)
+ goto error;
+ for (i = 0; i < total + div; ++i)
+ reordering[i] = i;
+ for (i = total + div + 1; i < total + qp->div->n_row; ++i)
+ reordering[i] = i - 1;
+ qp->div = isl_mat_drop_rows(qp->div, div, 1);
+ qp->div = isl_mat_drop_cols(qp->div, 2 + total + div, 1);
+ qp->upoly = reorder(qp->upoly, reordering);
+ free(reordering);
+
+ if (!qp->upoly || !qp->div)
+ goto error;
+
+ isl_upoly_free(s);
+ return qp;
+error:
+ isl_qpolynomial_free(qp);
+ isl_upoly_free(s);
+ return NULL;
+}
+
+/* Replace all integer divisions [e/d] that turn out to not actually be integer
+ * divisions because d is equal to 1 by their definition, i.e., e.
+ */
+static __isl_give isl_qpolynomial *substitute_non_divs(
+ __isl_take isl_qpolynomial *qp)
+{
+ int i, j;
+ int total;
+ struct isl_upoly *s;
+
+ if (!qp)
+ return NULL;
+
+ total = isl_dim_total(qp->dim);
+ for (i = 0; qp && i < qp->div->n_row; ++i) {
+ if (!isl_int_is_one(qp->div->row[i][0]))
+ continue;
+ 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],
+ qp->div->row[i] + 1, 1 + total + i);
+ isl_int_set_si(qp->div->row[j][2 + total + i], 0);
+ normalize_div(qp, j);
+ }
+ 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);
+ --i;
+ }
+
+ return qp;
+}
+
__isl_give isl_qpolynomial *isl_qpolynomial_substitute_equalities(
__isl_take isl_qpolynomial *qp, __isl_take isl_basic_set *eq)
{
int i, j, k;
isl_int denom;
unsigned total;
+ unsigned n_div;
struct isl_upoly *up;
if (!eq)
goto error;
total = 1 + isl_dim_total(eq->dim);
+ n_div = eq->n_div;
isl_int_init(denom);
for (i = 0; i < eq->n_eq; ++i) {
- j = isl_seq_last_non_zero(eq->eq[i], total);
- if (j < 0 || j == 0)
+ j = isl_seq_last_non_zero(eq->eq[i], total + n_div);
+ if (j < 0 || j == 0 || j >= total)
continue;
for (k = 0; k < qp->div->n_row; ++k) {
continue;
isl_seq_elim(qp->div->row[k] + 1, eq->eq[i], j, total,
&qp->div->row[k][0]);
- isl_seq_normalize(qp->div->ctx,
- qp->div->row[k], 1 + total);
+ normalize_div(qp, k);
}
if (isl_int_is_pos(eq->eq[i][j]))
isl_basic_set_free(eq);
+ qp = substitute_non_divs(qp);
qp = sort_divs(qp);
return qp;
return NULL;
}
-__isl_give isl_basic_set *add_div_constraints(__isl_take isl_basic_set *bset,
- __isl_take isl_mat *div)
+static __isl_give isl_basic_set *add_div_constraints(
+ __isl_take isl_basic_set *bset, __isl_take isl_mat *div)
{
int i;
unsigned total;
__isl_take isl_morph *morph)
{
int i;
+ int n_sub;
isl_ctx *ctx;
struct isl_upoly *up;
unsigned n_div;
ctx = qp->dim->ctx;
isl_assert(ctx, isl_dim_equal(qp->dim, morph->dom->dim), goto error);
- subs = isl_calloc_array(ctx, struct isl_upoly *, morph->inv->n_row - 1);
+ n_sub = morph->inv->n_row - 1;
+ if (morph->inv->n_row != morph->inv->n_col)
+ n_sub += qp->div->n_row;
+ subs = isl_calloc_array(ctx, struct isl_upoly *, n_sub);
if (!subs)
goto error;
for (i = 0; 1 + i < morph->inv->n_row; ++i)
subs[i] = isl_upoly_from_affine(ctx, morph->inv->row[1 + i],
morph->inv->row[0][0], morph->inv->n_col);
+ if (morph->inv->n_row != morph->inv->n_col)
+ for (i = 0; i < qp->div->n_row; ++i)
+ subs[morph->inv->n_row - 1 + i] =
+ isl_upoly_pow(ctx, morph->inv->n_col - 1 + i, 1);
- qp->upoly = isl_upoly_subs(qp->upoly, 0, morph->inv->n_row - 1, subs);
+ qp->upoly = isl_upoly_subs(qp->upoly, 0, n_sub, subs);
- for (i = 0; 1 + i < morph->inv->n_row; ++i)
+ for (i = 0; i < n_sub; ++i)
isl_upoly_free(subs[i]);
free(subs);
struct isl_split_periods_data *data)
{
int i;
- int *reordering;
+ int total;
isl_set *slice;
struct isl_upoly *cst;
- int total;
slice = set_div_slice(isl_set_get_dim(set), qp, div, v);
set = isl_set_intersect(set, slice);
- qp = isl_qpolynomial_cow(qp);
if (!qp)
goto error;
- cst = isl_upoly_rat_cst(qp->dim->ctx, v, qp->dim->ctx->one);
- if (!cst)
- goto error;
total = isl_dim_total(qp->dim);
- qp->upoly = isl_upoly_subs(qp->upoly, total + div, 1, &cst);
- isl_upoly_free(cst);
- if (!qp->upoly)
- goto error;
- reordering = isl_alloc_array(qp->dim->ctx, int, total + qp->div->n_row);
- if (!reordering)
- goto error;
- for (i = 0; i < total + div; ++i)
- reordering[i] = i;
- for (i = total + div + 1; i < total + qp->div->n_row; ++i)
- reordering[i] = i - 1;
- qp->div = isl_mat_drop_rows(qp->div, div, 1);
- qp->div = isl_mat_drop_cols(qp->div, 2 + total + div, 1);
- qp->upoly = reorder(qp->upoly, reordering);
- free(reordering);
+ for (i = div + 1; i < qp->div->n_row; ++i) {
+ if (isl_int_is_zero(qp->div->row[i][2 + total + div]))
+ continue;
+ isl_int_addmul(qp->div->row[i][1],
+ qp->div->row[i][2 + total + div], v);
+ isl_int_set_si(qp->div->row[i][2 + total + div], 0);
+ }
- if (!qp->upoly || !qp->div)
- goto error;
+ cst = isl_upoly_rat_cst(qp->dim->ctx, v, qp->dim->ctx->one);
+ qp = substitute_div(qp, div, cst);
return split_periods(set, qp, data);
error:
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_dim *dim;
+ isl_qpolynomial *qp;
+
+ if (!bset)
+ return NULL;
+
+ bset = isl_basic_map_domain(isl_basic_map_from_range(bset));
+ dim = isl_basic_set_get_dim(bset);
+ if (cst < 0)
+ qp = isl_qpolynomial_infty(dim);
+ else if (cst == 0)
+ qp = isl_qpolynomial_zero(dim);
+ else
+ qp = isl_qpolynomial_one(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_dim *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_dim(bset);
+ dim = isl_dim_domain(dim);
+ set = isl_set_universe(isl_dim_copy(dim));
+ qp = isl_qpolynomial_one(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;
+ unsigned orig_nvar, final_nvar;
+
+ if (!bset)
+ return NULL;
+
+ if (isl_basic_set_fast_is_empty(bset))
+ return constant_on_domain(bset, 0);
+
+ orig_nvar = isl_basic_set_dim(bset, isl_dim_set);
+
+ if (orig_nvar == 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);
+
+ final_nvar = isl_basic_set_dim(bset, isl_dim_set);
+
+ pwqp = compressed_multiplicative_call(bset, fn);
+
+ morph = isl_morph_remove_dom_dims(morph, isl_dim_set, 0, orig_nvar);
+ morph = isl_morph_remove_ran_dims(morph, isl_dim_set, 0, final_nvar);
+ morph = isl_morph_inverse(morph);
+
+ pwqp = isl_pw_qpolynomial_morph(pwqp, morph);
+
+ return pwqp;
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}