X-Git-Url: http://review.tizen.org/git/?p=platform%2Fupstream%2Fisl.git;a=blobdiff_plain;f=isl_fold.c;h=82cad6f48f4b890da45416f351a3b977a5f1ed89;hp=5d5caad1717fabbd6740cec012740c94462dae6f;hb=63fb8a7f484648c3caa25351c8c94ac2395ec563;hpb=8113984dd153adf8555b9be486e02fa6d238ebb6 diff --git a/isl_fold.c b/isl_fold.c index 5d5caad..82cad6f 100644 --- a/isl_fold.c +++ b/isl_fold.c @@ -1,22 +1,40 @@ /* * Copyright 2010 INRIA Saclay * - * Use of this software is governed by the GNU LGPLv2.1 license + * Use of this software is governed by the MIT license * * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, * 91893 Orsay, France */ +#define ISL_DIM_H +#include +#include #include #include -#include -#include -#include -#include +#include +#include +#include +#include +#include + +enum isl_fold isl_fold_type_negate(enum isl_fold type) +{ + switch (type) { + case isl_fold_min: + return isl_fold_max; + case isl_fold_max: + return isl_fold_min; + case isl_fold_list: + return isl_fold_list; + } + + isl_die(NULL, isl_error_internal, "unhandled isl_fold type", abort()); +} static __isl_give isl_qpolynomial_fold *qpolynomial_fold_alloc( - enum isl_fold type, __isl_take isl_dim *dim, int n) + enum isl_fold type, __isl_take isl_space *dim, int n) { isl_qpolynomial_fold *fold; @@ -24,7 +42,7 @@ static __isl_give isl_qpolynomial_fold *qpolynomial_fold_alloc( goto error; isl_assert(dim->ctx, n >= 0, goto error); - fold = isl_alloc(dim->ctx, struct isl_qpolynomial_fold, + fold = isl_calloc(dim->ctx, struct isl_qpolynomial_fold, sizeof(struct isl_qpolynomial_fold) + (n - 1) * sizeof(struct isl_qpolynomial *)); if (!fold) @@ -38,10 +56,71 @@ static __isl_give isl_qpolynomial_fold *qpolynomial_fold_alloc( return fold; error: - isl_dim_free(dim); + isl_space_free(dim); + return NULL; +} + +isl_ctx *isl_qpolynomial_fold_get_ctx(__isl_keep isl_qpolynomial_fold *fold) +{ + return fold ? fold->dim->ctx : NULL; +} + +__isl_give isl_space *isl_qpolynomial_fold_get_domain_space( + __isl_keep isl_qpolynomial_fold *fold) +{ + return fold ? isl_space_copy(fold->dim) : NULL; +} + +__isl_give isl_space *isl_qpolynomial_fold_get_space( + __isl_keep isl_qpolynomial_fold *fold) +{ + isl_space *space; + if (!fold) + return NULL; + space = isl_space_copy(fold->dim); + space = isl_space_from_domain(space); + space = isl_space_add_dims(space, isl_dim_out, 1); + return space; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_domain_space( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim) +{ + int i; + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold || !dim) + goto error; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_reset_domain_space(fold->qp[i], + isl_space_copy(dim)); + if (!fold->qp[i]) + goto error; + } + + isl_space_free(fold->dim); + fold->dim = dim; + + return fold; +error: + isl_qpolynomial_fold_free(fold); + isl_space_free(dim); return NULL; } +/* Reset the space of "fold". This function is called from isl_pw_templ.c + * and doesn't know if the space of an element object is represented + * directly or through its domain. It therefore passes along both. + */ +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_space_and_domain( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space, + __isl_take isl_space *domain) +{ + isl_space_free(space); + return isl_qpolynomial_fold_reset_domain_space(fold, domain); +} + int isl_qpolynomial_fold_involves_dims(__isl_keep isl_qpolynomial_fold *fold, enum isl_dim_type type, unsigned first, unsigned n) { @@ -61,21 +140,50 @@ int isl_qpolynomial_fold_involves_dims(__isl_keep isl_qpolynomial_fold *fold, return 0; } +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_set_dim_name( + __isl_take isl_qpolynomial_fold *fold, + enum isl_dim_type type, unsigned pos, const char *s) +{ + int i; + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + return NULL; + fold->dim = isl_space_set_dim_name(fold->dim, type, pos, s); + if (!fold->dim) + goto error; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_set_dim_name(fold->qp[i], + type, pos, s); + if (!fold->qp[i]) + goto error; + } + + return fold; +error: + isl_qpolynomial_fold_free(fold); + return NULL; +} + __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_drop_dims( __isl_take isl_qpolynomial_fold *fold, enum isl_dim_type type, unsigned first, unsigned n) { int i; + enum isl_dim_type set_type; if (!fold) return NULL; if (n == 0) return fold; + set_type = type == isl_dim_in ? isl_dim_set : type; + fold = isl_qpolynomial_fold_cow(fold); if (!fold) return NULL; - fold->dim = isl_dim_drop(fold->dim, type, first, n); + fold->dim = isl_space_drop_dims(fold->dim, set_type, first, n); if (!fold->dim) goto error; @@ -92,6 +200,37 @@ error: return NULL; } +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_insert_dims( + __isl_take isl_qpolynomial_fold *fold, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + + if (!fold) + return NULL; + if (n == 0 && !isl_space_is_named_or_nested(fold->dim, type)) + return fold; + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + return NULL; + fold->dim = isl_space_insert_dims(fold->dim, type, first, n); + if (!fold->dim) + goto error; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_insert_dims(fold->qp[i], + type, first, n); + if (!fold->qp[i]) + goto error; + } + + return fold; +error: + isl_qpolynomial_fold_free(fold); + return NULL; +} + static int isl_qpolynomial_cst_sign(__isl_keep isl_qpolynomial *qp) { struct isl_upoly_cst *cst; @@ -189,7 +328,7 @@ static int isl_qpolynomial_sign(__isl_keep isl_set *set, if (!rec) return 0; - d = isl_dim_total(qp->dim); + d = isl_space_dim(qp->dim, isl_dim_all); v = isl_vec_alloc(set->ctx, 2 + d); if (!v) return 0; @@ -207,17 +346,17 @@ static int isl_qpolynomial_sign(__isl_keep isl_set *set, isl_qpolynomial *r, *q; isl_qpolynomial *t; - min = isl_qpolynomial_cst(isl_dim_copy(qp->dim), l); - base = isl_qpolynomial_pow(isl_dim_copy(qp->dim), + min = isl_qpolynomial_cst_on_domain(isl_space_copy(qp->dim), l); + base = isl_qpolynomial_var_pow_on_domain(isl_space_copy(qp->dim), qp->upoly->var, 1); - r = isl_qpolynomial_alloc(isl_dim_copy(qp->dim), 0, + r = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0, isl_upoly_copy(rec->p[rec->n - 1])); q = isl_qpolynomial_copy(r); for (i = rec->n - 2; i >= 0; --i) { r = isl_qpolynomial_mul(r, isl_qpolynomial_copy(min)); - t = isl_qpolynomial_alloc(isl_dim_copy(qp->dim), 0, + t = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0, isl_upoly_copy(rec->p[i])); r = isl_qpolynomial_add(r, t); if (i == 0) @@ -265,7 +404,7 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold_on_domain( goto error; isl_assert(fold1->dim->ctx, fold1->type == fold2->type, goto error); - isl_assert(fold1->dim->ctx, isl_dim_equal(fold1->dim, fold2->dim), + isl_assert(fold1->dim->ctx, isl_space_is_equal(fold1->dim, fold2->dim), goto error); better = fold1->type == isl_fold_max ? -1 : 1; @@ -280,7 +419,7 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold_on_domain( return fold1; } - res = qpolynomial_fold_alloc(fold1->type, isl_dim_copy(fold1->dim), + res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim), fold1->n + fold2->n); if (!res) goto error; @@ -333,21 +472,190 @@ error: return NULL; } +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_qpolynomial( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_qpolynomial *qp) +{ + int i; + + if (!fold || !qp) + goto error; + + if (isl_qpolynomial_is_zero(qp)) { + isl_qpolynomial_free(qp); + return fold; + } + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + goto error; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_add(fold->qp[i], + isl_qpolynomial_copy(qp)); + if (!fold->qp[i]) + goto error; + } + + isl_qpolynomial_free(qp); + return fold; +error: + isl_qpolynomial_fold_free(fold); + isl_qpolynomial_free(qp); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_on_domain( + __isl_keep isl_set *dom, + __isl_take isl_qpolynomial_fold *fold1, + __isl_take isl_qpolynomial_fold *fold2) +{ + int i; + isl_qpolynomial_fold *res = NULL; + + if (!fold1 || !fold2) + goto error; + + if (isl_qpolynomial_fold_is_empty(fold1)) { + isl_qpolynomial_fold_free(fold1); + return fold2; + } + + if (isl_qpolynomial_fold_is_empty(fold2)) { + isl_qpolynomial_fold_free(fold2); + return fold1; + } + + if (fold1->n == 1 && fold2->n != 1) + return isl_qpolynomial_fold_add_on_domain(dom, fold2, fold1); + + if (fold2->n == 1) { + res = isl_qpolynomial_fold_add_qpolynomial(fold1, + isl_qpolynomial_copy(fold2->qp[0])); + isl_qpolynomial_fold_free(fold2); + return res; + } + + res = isl_qpolynomial_fold_add_qpolynomial( + isl_qpolynomial_fold_copy(fold1), + isl_qpolynomial_copy(fold2->qp[0])); + + for (i = 1; i < fold2->n; ++i) { + isl_qpolynomial_fold *res_i; + res_i = isl_qpolynomial_fold_add_qpolynomial( + isl_qpolynomial_fold_copy(fold1), + isl_qpolynomial_copy(fold2->qp[i])); + res = isl_qpolynomial_fold_fold_on_domain(dom, res, res_i); + } + + isl_qpolynomial_fold_free(fold1); + isl_qpolynomial_fold_free(fold2); + return res; +error: + isl_qpolynomial_fold_free(res); + isl_qpolynomial_fold_free(fold1); + isl_qpolynomial_fold_free(fold2); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute_equalities( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_basic_set *eq) +{ + int i; + + if (!fold || !eq) + goto error; + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + return NULL; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_substitute_equalities(fold->qp[i], + isl_basic_set_copy(eq)); + if (!fold->qp[i]) + goto error; + } + + isl_basic_set_free(eq); + return fold; +error: + isl_basic_set_free(eq); + isl_qpolynomial_fold_free(fold); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context) +{ + int i; + + if (!fold || !context) + goto error; + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + return NULL; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_gist(fold->qp[i], + isl_set_copy(context)); + if (!fold->qp[i]) + goto error; + } + + isl_set_free(context); + return fold; +error: + isl_set_free(context); + isl_qpolynomial_fold_free(fold); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist_params( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context) +{ + isl_space *space = isl_qpolynomial_fold_get_domain_space(fold); + isl_set *dom_context = isl_set_universe(space); + dom_context = isl_set_intersect_params(dom_context, context); + return isl_qpolynomial_fold_gist(fold, dom_context); +} + +#define HAS_TYPE + #undef PW #define PW isl_pw_qpolynomial_fold #undef EL #define EL isl_qpolynomial_fold +#undef EL_IS_ZERO +#define EL_IS_ZERO is_empty +#undef ZERO +#define ZERO zero #undef IS_ZERO -#define IS_ZERO is_empty +#define IS_ZERO is_zero #undef FIELD #define FIELD fold -#undef ADD -#define ADD(d,e1,e2) isl_qpolynomial_fold_fold_on_domain(d,e1,e2) +#undef DEFAULT_IS_ZERO +#define DEFAULT_IS_ZERO 1 + +#define NO_NEG +#define NO_PULLBACK #include +#undef UNION +#define UNION isl_union_pw_qpolynomial_fold +#undef PART +#define PART isl_pw_qpolynomial_fold +#undef PARTS +#define PARTS pw_qpolynomial_fold +#define ALIGN_DOMAIN + +#define NO_SUB + +#include + __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_empty(enum isl_fold type, - __isl_take isl_dim *dim) + __isl_take isl_space *dim) { return qpolynomial_fold_alloc(type, dim, 0); } @@ -360,7 +668,7 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_alloc( if (!qp) return NULL; - fold = qpolynomial_fold_alloc(type, isl_dim_copy(qp->dim), 1); + fold = qpolynomial_fold_alloc(type, isl_space_copy(qp->dim), 1); if (!fold) goto error; @@ -393,10 +701,11 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_dup( if (!fold) return NULL; dup = qpolynomial_fold_alloc(fold->type, - isl_dim_copy(fold->dim), fold->n); + isl_space_copy(fold->dim), fold->n); if (!dup) return NULL; + dup->n = fold->n; for (i = 0; i < fold->n; ++i) { dup->qp[i] = isl_qpolynomial_copy(fold->qp[i]); if (!dup->qp[i]) @@ -432,7 +741,7 @@ void isl_qpolynomial_fold_free(__isl_take isl_qpolynomial_fold *fold) for (i = 0; i < fold->n; ++i) isl_qpolynomial_free(fold->qp[i]); - isl_dim_free(fold->dim); + isl_space_free(fold->dim); free(fold); } @@ -455,7 +764,7 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold( goto error; isl_assert(fold1->dim->ctx, fold1->type == fold2->type, goto error); - isl_assert(fold1->dim->ctx, isl_dim_equal(fold1->dim, fold2->dim), + isl_assert(fold1->dim->ctx, isl_space_is_equal(fold1->dim, fold2->dim), goto error); if (isl_qpolynomial_fold_is_empty(fold1)) { @@ -468,7 +777,7 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold( return fold1; } - res = qpolynomial_fold_alloc(fold1->type, isl_dim_copy(fold1->dim), + res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim), fold1->n + fold2->n); if (!res) goto error; @@ -498,6 +807,149 @@ error: return NULL; } +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fold( + __isl_take isl_pw_qpolynomial_fold *pw1, + __isl_take isl_pw_qpolynomial_fold *pw2) +{ + int i, j, n; + struct isl_pw_qpolynomial_fold *res; + isl_set *set; + + if (!pw1 || !pw2) + goto error; + + isl_assert(pw1->dim->ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error); + + if (isl_pw_qpolynomial_fold_is_zero(pw1)) { + isl_pw_qpolynomial_fold_free(pw1); + return pw2; + } + + if (isl_pw_qpolynomial_fold_is_zero(pw2)) { + isl_pw_qpolynomial_fold_free(pw2); + return pw1; + } + + if (pw1->type != pw2->type) + isl_die(pw1->dim->ctx, isl_error_invalid, + "fold types don't match", goto error); + + n = (pw1->n + 1) * (pw2->n + 1); + res = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pw1->dim), + pw1->type, n); + + for (i = 0; i < pw1->n; ++i) { + set = isl_set_copy(pw1->p[i].set); + for (j = 0; j < pw2->n; ++j) { + struct isl_set *common; + isl_qpolynomial_fold *sum; + set = isl_set_subtract(set, + isl_set_copy(pw2->p[j].set)); + common = isl_set_intersect(isl_set_copy(pw1->p[i].set), + isl_set_copy(pw2->p[j].set)); + if (isl_set_plain_is_empty(common)) { + isl_set_free(common); + continue; + } + + sum = isl_qpolynomial_fold_fold_on_domain(common, + isl_qpolynomial_fold_copy(pw1->p[i].fold), + isl_qpolynomial_fold_copy(pw2->p[j].fold)); + + res = isl_pw_qpolynomial_fold_add_piece(res, common, sum); + } + res = isl_pw_qpolynomial_fold_add_piece(res, set, + isl_qpolynomial_fold_copy(pw1->p[i].fold)); + } + + for (j = 0; j < pw2->n; ++j) { + set = isl_set_copy(pw2->p[j].set); + for (i = 0; i < pw1->n; ++i) + set = isl_set_subtract(set, isl_set_copy(pw1->p[i].set)); + res = isl_pw_qpolynomial_fold_add_piece(res, set, + isl_qpolynomial_fold_copy(pw2->p[j].fold)); + } + + isl_pw_qpolynomial_fold_free(pw1); + isl_pw_qpolynomial_fold_free(pw2); + + return res; +error: + isl_pw_qpolynomial_fold_free(pw1); + isl_pw_qpolynomial_fold_free(pw2); + return NULL; +} + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold( + __isl_take isl_union_pw_qpolynomial_fold *u, + __isl_take isl_pw_qpolynomial_fold *part) +{ + uint32_t hash; + struct isl_hash_table_entry *entry; + + u = isl_union_pw_qpolynomial_fold_cow(u); + + if (!part || !u) + goto error; + + isl_assert(u->dim->ctx, isl_space_match(part->dim, isl_dim_param, u->dim, + isl_dim_param), goto error); + + hash = isl_space_get_hash(part->dim); + entry = isl_hash_table_find(u->dim->ctx, &u->table, hash, + &has_dim, part->dim, 1); + if (!entry) + goto error; + + if (!entry->data) + entry->data = part; + else { + entry->data = isl_pw_qpolynomial_fold_fold(entry->data, + isl_pw_qpolynomial_fold_copy(part)); + if (!entry->data) + goto error; + isl_pw_qpolynomial_fold_free(part); + } + + return u; +error: + isl_pw_qpolynomial_fold_free(part); + isl_union_pw_qpolynomial_fold_free(u); + return NULL; +} + +static int fold_part(__isl_take isl_pw_qpolynomial_fold *part, void *user) +{ + isl_union_pw_qpolynomial_fold **u; + u = (isl_union_pw_qpolynomial_fold **)user; + + *u = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(*u, part); + + return 0; +} + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold( + __isl_take isl_union_pw_qpolynomial_fold *u1, + __isl_take isl_union_pw_qpolynomial_fold *u2) +{ + u1 = isl_union_pw_qpolynomial_fold_cow(u1); + + if (!u1 || !u2) + goto error; + + if (isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(u2, + &fold_part, &u1) < 0) + goto error; + + isl_union_pw_qpolynomial_fold_free(u2); + + return u1; +error: + isl_union_pw_qpolynomial_fold_free(u1); + isl_union_pw_qpolynomial_fold_free(u2); + return NULL; +} + __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_from_pw_qpolynomial( enum isl_fold type, __isl_take isl_pw_qpolynomial *pwqp) { @@ -507,7 +959,8 @@ __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_from_pw_qpolynomial( if (!pwqp) return NULL; - pwf = isl_pw_qpolynomial_fold_alloc_(isl_dim_copy(pwqp->dim), pwqp->n); + pwf = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pwqp->dim), + type, pwqp->n); for (i = 0; i < pwqp->n; ++i) pwf = isl_pw_qpolynomial_fold_add_piece(pwf, @@ -520,7 +973,14 @@ __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_from_pw_qpolynomial( return pwf; } -int isl_qpolynomial_fold_is_equal(__isl_keep isl_qpolynomial_fold *fold1, +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add( + __isl_take isl_pw_qpolynomial_fold *pwf1, + __isl_take isl_pw_qpolynomial_fold *pwf2) +{ + return isl_pw_qpolynomial_fold_union_add_(pwf1, pwf2); +} + +int isl_qpolynomial_fold_plain_is_equal(__isl_keep isl_qpolynomial_fold *fold1, __isl_keep isl_qpolynomial_fold *fold2) { int i; @@ -533,7 +993,7 @@ int isl_qpolynomial_fold_is_equal(__isl_keep isl_qpolynomial_fold *fold1, /* We probably want to sort the qps first... */ for (i = 0; i < fold1->n; ++i) { - int eq = isl_qpolynomial_is_equal(fold1->qp[i], fold2->qp[i]); + int eq = isl_qpolynomial_plain_is_equal(fold1->qp[i], fold2->qp[i]); if (eq < 0 || !eq) return eq; } @@ -548,13 +1008,13 @@ __isl_give isl_qpolynomial *isl_qpolynomial_fold_eval( if (!fold || !pnt) goto error; - isl_assert(pnt->dim->ctx, isl_dim_equal(pnt->dim, fold->dim), goto error); + isl_assert(pnt->dim->ctx, isl_space_is_equal(pnt->dim, fold->dim), goto error); isl_assert(pnt->dim->ctx, fold->type == isl_fold_max || fold->type == isl_fold_min, goto error); if (fold->n == 0) - qp = isl_qpolynomial_zero(isl_dim_copy(fold->dim)); + qp = isl_qpolynomial_zero_on_domain(isl_space_copy(fold->dim)); else { int i; qp = isl_qpolynomial_eval(isl_qpolynomial_copy(fold->qp[0]), @@ -601,10 +1061,10 @@ __isl_give isl_qpolynomial *isl_qpolynomial_fold_opt_on_domain( goto error; if (fold->n == 0) { - isl_dim *dim = isl_dim_copy(fold->dim); + isl_space *dim = isl_space_copy(fold->dim); isl_set_free(set); isl_qpolynomial_fold_free(fold); - return isl_qpolynomial_zero(dim); + return isl_qpolynomial_zero_on_domain(dim); } opt = isl_qpolynomial_opt_on_domain(isl_qpolynomial_copy(fold->qp[0]), @@ -719,7 +1179,7 @@ int isl_pw_qpolynomial_fold_covers(__isl_keep isl_pw_qpolynomial_fold *pwf1, return 1; } -__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_morph( +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_morph_domain( __isl_take isl_qpolynomial_fold *fold, __isl_take isl_morph *morph) { int i; @@ -729,19 +1189,19 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_morph( goto error; ctx = fold->dim->ctx; - isl_assert(ctx, isl_dim_equal(fold->dim, morph->dom->dim), goto error); + isl_assert(ctx, isl_space_is_equal(fold->dim, morph->dom->dim), goto error); fold = isl_qpolynomial_fold_cow(fold); if (!fold) goto error; - isl_dim_free(fold->dim); - fold->dim = isl_dim_copy(morph->ran->dim); + isl_space_free(fold->dim); + fold->dim = isl_space_copy(morph->ran->dim); if (!fold->dim) goto error; for (i = 0; i < fold->n; ++i) { - fold->qp[i] = isl_qpolynomial_morph(fold->qp[i], + fold->qp[i] = isl_qpolynomial_morph_domain(fold->qp[i], isl_morph_copy(morph)); if (!fold->qp[i]) goto error; @@ -756,6 +1216,75 @@ error: return NULL; } +enum isl_fold isl_qpolynomial_fold_get_type(__isl_keep isl_qpolynomial_fold *fold) +{ + if (!fold) + return isl_fold_list; + return fold->type; +} + +enum isl_fold isl_union_pw_qpolynomial_fold_get_type( + __isl_keep isl_union_pw_qpolynomial_fold *upwf) +{ + if (!upwf) + return isl_fold_list; + return upwf->type; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_lift( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim) +{ + int i; + + if (!fold || !dim) + goto error; + + if (isl_space_is_equal(fold->dim, dim)) { + isl_space_free(dim); + return fold; + } + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + goto error; + + isl_space_free(fold->dim); + fold->dim = isl_space_copy(dim); + if (!fold->dim) + goto error; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_lift(fold->qp[i], + isl_space_copy(dim)); + if (!fold->qp[i]) + goto error; + } + + isl_space_free(dim); + + return fold; +error: + isl_qpolynomial_fold_free(fold); + isl_space_free(dim); + return NULL; +} + +int isl_qpolynomial_fold_foreach_qpolynomial( + __isl_keep isl_qpolynomial_fold *fold, + int (*fn)(__isl_take isl_qpolynomial *qp, void *user), void *user) +{ + int i; + + if (!fold) + return -1; + + for (i = 0; i < fold->n; ++i) + if (fn(isl_qpolynomial_copy(fold->qp[i]), user) < 0) + return -1; + + return 0; +} + __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims( __isl_take isl_qpolynomial_fold *fold, enum isl_dim_type dst_type, unsigned dst_pos, @@ -770,7 +1299,7 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims( if (!fold) return NULL; - fold->dim = isl_dim_move(fold->dim, dst_type, dst_pos, + fold->dim = isl_space_move_dims(fold->dim, dst_type, dst_pos, src_type, src_pos, n); if (!fold->dim) goto error; @@ -787,3 +1316,317 @@ error: isl_qpolynomial_fold_free(fold); return NULL; } + +/* For each 0 <= i < "n", replace variable "first" + i of type "type" + * in fold->qp[k] by subs[i]. + */ +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute( + __isl_take isl_qpolynomial_fold *fold, + enum isl_dim_type type, unsigned first, unsigned n, + __isl_keep isl_qpolynomial **subs) +{ + int i; + + if (n == 0) + return fold; + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + return NULL; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_substitute(fold->qp[i], + type, first, n, subs); + if (!fold->qp[i]) + goto error; + } + + return fold; +error: + isl_qpolynomial_fold_free(fold); + return NULL; +} + +static int add_pwqp(__isl_take isl_pw_qpolynomial *pwqp, void *user) +{ + isl_ctx *ctx; + isl_pw_qpolynomial_fold *pwf; + isl_union_pw_qpolynomial_fold **upwf; + uint32_t hash; + struct isl_hash_table_entry *entry; + + upwf = (isl_union_pw_qpolynomial_fold **)user; + + ctx = pwqp->dim->ctx; + hash = isl_space_get_hash(pwqp->dim); + entry = isl_hash_table_find(ctx, &(*upwf)->table, + hash, &has_dim, pwqp->dim, 1); + if (!entry) + goto error; + + pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial((*upwf)->type, pwqp); + if (!entry->data) + entry->data = pwf; + else { + entry->data = isl_pw_qpolynomial_fold_add(entry->data, pwf); + if (!entry->data) + return -1; + if (isl_pw_qpolynomial_fold_is_zero(entry->data)) { + isl_pw_qpolynomial_fold_free(entry->data); + isl_hash_table_remove(ctx, &(*upwf)->table, entry); + } + } + + return 0; +error: + isl_pw_qpolynomial_free(pwqp); + return -1; +} + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_add_union_pw_qpolynomial( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_union_pw_qpolynomial *upwqp) +{ + upwf = isl_union_pw_qpolynomial_fold_align_params(upwf, + isl_union_pw_qpolynomial_get_space(upwqp)); + upwqp = isl_union_pw_qpolynomial_align_params(upwqp, + isl_union_pw_qpolynomial_fold_get_space(upwf)); + + upwf = isl_union_pw_qpolynomial_fold_cow(upwf); + if (!upwf || !upwqp) + goto error; + + if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, &add_pwqp, + &upwf) < 0) + goto error; + + isl_union_pw_qpolynomial_free(upwqp); + + return upwf; +error: + isl_union_pw_qpolynomial_fold_free(upwf); + isl_union_pw_qpolynomial_free(upwqp); + return NULL; +} + +static int join_compatible(__isl_keep isl_space *dim1, __isl_keep isl_space *dim2) +{ + int m; + m = isl_space_match(dim1, isl_dim_param, dim2, isl_dim_param); + if (m < 0 || !m) + return m; + return isl_space_tuple_match(dim1, isl_dim_out, dim2, isl_dim_in); +} + +/* Compute the intersection of the range of the map and the domain + * of the piecewise quasipolynomial reduction and then compute a bound + * on the associated quasipolynomial reduction over all elements + * in this intersection. + * + * We first introduce some unconstrained dimensions in the + * piecewise quasipolynomial, intersect the resulting domain + * with the wrapped map and the compute the sum. + */ +__isl_give isl_pw_qpolynomial_fold *isl_map_apply_pw_qpolynomial_fold( + __isl_take isl_map *map, __isl_take isl_pw_qpolynomial_fold *pwf, + int *tight) +{ + isl_ctx *ctx; + isl_set *dom; + isl_space *map_dim; + isl_space *pwf_dim; + unsigned n_in; + int ok; + + ctx = isl_map_get_ctx(map); + if (!ctx) + goto error; + + map_dim = isl_map_get_space(map); + pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf); + ok = join_compatible(map_dim, pwf_dim); + isl_space_free(map_dim); + isl_space_free(pwf_dim); + if (!ok) + isl_die(ctx, isl_error_invalid, "incompatible dimensions", + goto error); + + n_in = isl_map_dim(map, isl_dim_in); + pwf = isl_pw_qpolynomial_fold_insert_dims(pwf, isl_dim_in, 0, n_in); + + dom = isl_map_wrap(map); + pwf = isl_pw_qpolynomial_fold_reset_domain_space(pwf, + isl_set_get_space(dom)); + + pwf = isl_pw_qpolynomial_fold_intersect_domain(pwf, dom); + pwf = isl_pw_qpolynomial_fold_bound(pwf, tight); + + return pwf; +error: + isl_map_free(map); + isl_pw_qpolynomial_fold_free(pwf); + return NULL; +} + +__isl_give isl_pw_qpolynomial_fold *isl_set_apply_pw_qpolynomial_fold( + __isl_take isl_set *set, __isl_take isl_pw_qpolynomial_fold *pwf, + int *tight) +{ + return isl_map_apply_pw_qpolynomial_fold(set, pwf, tight); +} + +struct isl_apply_fold_data { + isl_union_pw_qpolynomial_fold *upwf; + isl_union_pw_qpolynomial_fold *res; + isl_map *map; + int tight; +}; + +static int pw_qpolynomial_fold_apply(__isl_take isl_pw_qpolynomial_fold *pwf, + void *user) +{ + isl_space *map_dim; + isl_space *pwf_dim; + struct isl_apply_fold_data *data = user; + int ok; + + map_dim = isl_map_get_space(data->map); + pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf); + ok = join_compatible(map_dim, pwf_dim); + isl_space_free(map_dim); + isl_space_free(pwf_dim); + + if (ok) { + pwf = isl_map_apply_pw_qpolynomial_fold(isl_map_copy(data->map), + pwf, data->tight ? &data->tight : NULL); + data->res = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold( + data->res, pwf); + } else + isl_pw_qpolynomial_fold_free(pwf); + + return 0; +} + +static int map_apply(__isl_take isl_map *map, void *user) +{ + struct isl_apply_fold_data *data = user; + int r; + + data->map = map; + r = isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold( + data->upwf, &pw_qpolynomial_fold_apply, data); + + isl_map_free(map); + return r; +} + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_map_apply_union_pw_qpolynomial_fold( + __isl_take isl_union_map *umap, + __isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight) +{ + isl_space *dim; + enum isl_fold type; + struct isl_apply_fold_data data; + + upwf = isl_union_pw_qpolynomial_fold_align_params(upwf, + isl_union_map_get_space(umap)); + umap = isl_union_map_align_params(umap, + isl_union_pw_qpolynomial_fold_get_space(upwf)); + + data.upwf = upwf; + data.tight = tight ? 1 : 0; + dim = isl_union_pw_qpolynomial_fold_get_space(upwf); + type = isl_union_pw_qpolynomial_fold_get_type(upwf); + data.res = isl_union_pw_qpolynomial_fold_zero(dim, type); + if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0) + goto error; + + isl_union_map_free(umap); + isl_union_pw_qpolynomial_fold_free(upwf); + + if (tight) + *tight = data.tight; + + return data.res; +error: + isl_union_map_free(umap); + isl_union_pw_qpolynomial_fold_free(upwf); + isl_union_pw_qpolynomial_fold_free(data.res); + return NULL; +} + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_set_apply_union_pw_qpolynomial_fold( + __isl_take isl_union_set *uset, + __isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight) +{ + return isl_union_map_apply_union_pw_qpolynomial_fold(uset, upwf, tight); +} + +/* Reorder the dimension of "fold" according to the given reordering. + */ +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_realign_domain( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_reordering *r) +{ + int i; + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold || !r) + goto error; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_realign_domain(fold->qp[i], + isl_reordering_copy(r)); + if (!fold->qp[i]) + goto error; + } + + fold = isl_qpolynomial_fold_reset_domain_space(fold, + isl_space_copy(r->dim)); + + isl_reordering_free(r); + + return fold; +error: + isl_qpolynomial_fold_free(fold); + isl_reordering_free(r); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_mul_isl_int( + __isl_take isl_qpolynomial_fold *fold, isl_int v) +{ + int i; + + if (isl_int_is_one(v)) + return fold; + if (fold && isl_int_is_zero(v)) { + isl_qpolynomial_fold *zero; + isl_space *dim = isl_space_copy(fold->dim); + zero = isl_qpolynomial_fold_empty(fold->type, dim); + isl_qpolynomial_fold_free(fold); + return zero; + } + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + return NULL; + + if (isl_int_is_neg(v)) + fold->type = isl_fold_type_negate(fold->type); + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_mul_isl_int(fold->qp[i], v); + if (!fold->qp[i]) + goto error; + } + + return fold; +error: + isl_qpolynomial_fold_free(fold); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale( + __isl_take isl_qpolynomial_fold *fold, isl_int v) +{ + return isl_qpolynomial_fold_mul_isl_int(fold, v); +}