summaryrefslogtreecommitdiff
path: root/isl_multi_templ.c
diff options
context:
space:
mode:
Diffstat (limited to 'isl_multi_templ.c')
-rw-r--r--isl_multi_templ.c567
1 files changed, 551 insertions, 16 deletions
diff --git a/isl_multi_templ.c b/isl_multi_templ.c
index d73eb500..c0291862 100644
--- a/isl_multi_templ.c
+++ b/isl_multi_templ.c
@@ -1,6 +1,6 @@
/*
* Copyright 2011 Sven Verdoolaege
- * Copyright 2012 Ecole Normale Superieure
+ * Copyright 2012-2013 Ecole Normale Superieure
*
* Use of this software is governed by the MIT license
*
@@ -105,7 +105,7 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),copy)(__isl_keep MULTI(BASE) *multi)
return multi;
}
-void *FN(MULTI(BASE),free)(__isl_take MULTI(BASE) *multi)
+__isl_null MULTI(BASE) *FN(MULTI(BASE),free)(__isl_take MULTI(BASE) *multi)
{
int i;
@@ -123,6 +123,31 @@ void *FN(MULTI(BASE),free)(__isl_take MULTI(BASE) *multi)
return NULL;
}
+/* Check whether "multi" has non-zero coefficients for any dimension
+ * in the given range or if any of these dimensions appear
+ * with non-zero coefficients in any of the integer divisions involved.
+ */
+int FN(MULTI(BASE),involves_dims)(__isl_keep MULTI(BASE) *multi,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ int i;
+
+ if (!multi)
+ return -1;
+ if (multi->n == 0 || n == 0)
+ return 0;
+
+ for (i = 0; i < multi->n; ++i) {
+ int involves;
+
+ involves = FN(EL,involves_dims)(multi->p[i], type, first, n);
+ if (involves < 0 || involves)
+ return involves;
+ }
+
+ return 0;
+}
+
__isl_give MULTI(BASE) *FN(MULTI(BASE),insert_dims)(
__isl_take MULTI(BASE) *multi,
enum isl_dim_type type, unsigned first, unsigned n)
@@ -171,6 +196,25 @@ unsigned FN(MULTI(BASE),dim)(__isl_keep MULTI(BASE) *multi,
return multi ? isl_space_dim(multi->space, type) : 0;
}
+/* Return the position of the first dimension of "type" with id "id".
+ * Return -1 if there is no such dimension.
+ */
+int FN(MULTI(BASE),find_dim_by_id)(__isl_keep MULTI(BASE) *multi,
+ enum isl_dim_type type, __isl_keep isl_id *id)
+{
+ if (!multi)
+ return -1;
+ return isl_space_find_dim_by_id(multi->space, type, id);
+}
+
+/* Return the id of the given dimension.
+ */
+__isl_give isl_id *FN(MULTI(BASE),get_dim_id)(__isl_keep MULTI(BASE) *multi,
+ enum isl_dim_type type, unsigned pos)
+{
+ return multi ? isl_space_get_dim_id(multi->space, type, pos) : NULL;
+}
+
__isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_name)(
__isl_take MULTI(BASE) *multi,
enum isl_dim_type type, unsigned pos, const char *s)
@@ -202,6 +246,22 @@ const char *FN(MULTI(BASE),get_tuple_name)(__isl_keep MULTI(BASE) *multi,
return multi ? isl_space_get_tuple_name(multi->space, type) : NULL;
}
+/* Does the specified tuple have an id?
+ */
+int FN(MULTI(BASE),has_tuple_id)(__isl_keep MULTI(BASE) *multi,
+ enum isl_dim_type type)
+{
+ return multi ? isl_space_has_tuple_id(multi->space, type) : -1;
+}
+
+/* Return the id of the specified tuple.
+ */
+__isl_give isl_id *FN(MULTI(BASE),get_tuple_id)(__isl_keep MULTI(BASE) *multi,
+ enum isl_dim_type type)
+{
+ return multi ? isl_space_get_tuple_id(multi->space, type) : NULL;
+}
+
__isl_give EL *FN(FN(MULTI(BASE),get),BASE)(__isl_keep MULTI(BASE) *multi,
int pos)
{
@@ -221,12 +281,23 @@ __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),set),BASE)(
{
isl_space *multi_space = NULL;
isl_space *el_space = NULL;
+ int match;
multi = FN(MULTI(BASE),cow)(multi);
if (!multi || !el)
goto error;
multi_space = FN(MULTI(BASE),get_space)(multi);
+ match = FN(EL,matching_params)(el, multi_space);
+ if (match < 0)
+ goto error;
+ if (!match) {
+ multi = FN(MULTI(BASE),align_params)(multi,
+ FN(EL,get_space)(el));
+ isl_space_free(multi_space);
+ multi_space = FN(MULTI(BASE),get_space)(multi);
+ el = FN(EL,align_params)(el, isl_space_copy(multi_space));
+ }
if (FN(EL,check_match_domain_space)(el, multi_space) < 0)
goto error;
@@ -302,6 +373,28 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space)(
return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
}
+/* Set the id of the given dimension of "multi" to "id".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_id)(
+ __isl_take MULTI(BASE) *multi,
+ enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+ isl_space *space;
+
+ multi = FN(MULTI(BASE),cow)(multi);
+ if (!multi || !id)
+ goto error;
+
+ space = FN(MULTI(BASE),get_space)(multi);
+ space = isl_space_set_dim_id(space, type, pos, id);
+
+ return FN(MULTI(BASE),reset_space)(multi, space);
+error:
+ isl_id_free(id);
+ FN(MULTI(BASE),free)(multi);
+ return NULL;
+}
+
__isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_name)(
__isl_keep MULTI(BASE) *multi, enum isl_dim_type type,
const char *s)
@@ -319,19 +412,58 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_name)(
}
__isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_id)(
- __isl_keep MULTI(BASE) *multi, enum isl_dim_type type,
+ __isl_take MULTI(BASE) *multi, enum isl_dim_type type,
__isl_take isl_id *id)
{
isl_space *space;
multi = FN(MULTI(BASE),cow)(multi);
if (!multi)
- return isl_id_free(id);
+ goto error;
space = FN(MULTI(BASE),get_space)(multi);
space = isl_space_set_tuple_id(space, type, id);
return FN(MULTI(BASE),reset_space)(multi, space);
+error:
+ isl_id_free(id);
+ return NULL;
+}
+
+/* Drop the id on the specified tuple.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_tuple_id)(
+ __isl_take MULTI(BASE) *multi, enum isl_dim_type type)
+{
+ isl_space *space;
+
+ if (!multi)
+ return NULL;
+ if (!FN(MULTI(BASE),has_tuple_id)(multi, type))
+ return multi;
+
+ multi = FN(MULTI(BASE),cow)(multi);
+ if (!multi)
+ return NULL;
+
+ space = FN(MULTI(BASE),get_space)(multi);
+ space = isl_space_reset_tuple_id(space, type);
+
+ return FN(MULTI(BASE),reset_space)(multi, space);
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of the space of "multi".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_user)(
+ __isl_take MULTI(BASE) *multi)
+{
+ isl_space *space;
+
+ space = FN(MULTI(BASE),get_space)(multi);
+ space = isl_space_reset_user(space);
+
+ return FN(MULTI(BASE),reset_space)(multi, space);
}
__isl_give MULTI(BASE) *FN(MULTI(BASE),realign_domain)(
@@ -367,10 +499,17 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params)(
__isl_take MULTI(BASE) *multi, __isl_take isl_space *model)
{
isl_ctx *ctx;
+ isl_reordering *exp;
if (!multi || !model)
goto error;
+ if (isl_space_match(multi->space, isl_dim_param,
+ model, isl_dim_param)) {
+ isl_space_free(model);
+ return multi;
+ }
+
ctx = isl_space_get_ctx(model);
if (!isl_space_has_named_params(model))
isl_die(ctx, isl_error_invalid,
@@ -378,16 +517,12 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params)(
if (!isl_space_has_named_params(multi->space))
isl_die(ctx, isl_error_invalid,
"input has unnamed parameters", goto error);
- if (!isl_space_match(multi->space, isl_dim_param,
- model, isl_dim_param)) {
- isl_reordering *exp;
- model = isl_space_params(model);
- exp = isl_parameter_alignment_reordering(multi->space, model);
- exp = isl_reordering_extend_space(exp,
+ model = isl_space_params(model);
+ exp = isl_parameter_alignment_reordering(multi->space, model);
+ exp = isl_reordering_extend_space(exp,
FN(MULTI(BASE),get_domain_space)(multi));
- multi = FN(MULTI(BASE),realign_domain)(multi, exp);
- }
+ multi = FN(MULTI(BASE),realign_domain)(multi, exp);
isl_space_free(model);
return multi;
@@ -397,7 +532,7 @@ error:
return NULL;
}
-#ifndef NO_GIST
+#if !defined(NO_GIST) || !defined(NO_INTERSECT_DOMAIN)
static __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params_multi_set_and)(
__isl_take MULTI(BASE) *multi, __isl_take isl_set *set,
__isl_give MULTI(BASE) *(*fn)(__isl_take MULTI(BASE) *multi,
@@ -423,7 +558,9 @@ error:
isl_set_free(set);
return NULL;
}
+#endif
+#ifndef NO_GIST
__isl_give MULTI(BASE) *FN(MULTI(BASE),gist_aligned)(
__isl_take MULTI(BASE) *multi, __isl_take isl_set *context)
{
@@ -464,6 +601,85 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),gist_params)(
}
#endif
+#ifndef NO_INTERSECT_DOMAIN
+/* Transform the domain of "multi" by combining it with "domain"
+ * using "fn".
+ *
+ * The parameters of "multi" and "domain" are assumed to have been aligned.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_aligned)(
+ __isl_take MULTI(BASE) *multi, __isl_take isl_set *domain,
+ __isl_give EL *(*fn)(EL *el, __isl_take isl_set *set2))
+{
+ int i;
+
+ if (!multi || !domain)
+ goto error;
+
+ if (multi->n == 0) {
+ isl_set_free(domain);
+ return multi;
+ }
+
+ multi = FN(MULTI(BASE),cow)(multi);
+ if (!multi)
+ goto error;
+
+ for (i = 0; i < multi->n; ++i) {
+ multi->p[i] = fn(multi->p[i], isl_set_copy(domain));
+ if (!multi->p[i])
+ goto error;
+ }
+
+ isl_set_free(domain);
+ return multi;
+error:
+ isl_set_free(domain);
+ FN(MULTI(BASE),free)(multi);
+ return NULL;
+}
+
+/* Intersect the domain of "multi" with "domain".
+ *
+ * The parameters of "multi" and "domain" are assumed to have been aligned.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_domain_aligned)(
+ __isl_take MULTI(BASE) *multi, __isl_take isl_set *domain)
+{
+ return FN(MULTI(BASE),intersect_aligned)(multi, domain,
+ &FN(EL,intersect_domain));
+}
+
+/* Intersect the domain of "multi" with "domain".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_domain)(
+ __isl_take MULTI(BASE) *multi, __isl_take isl_set *domain)
+{
+ return FN(MULTI(BASE),align_params_multi_set_and)(multi, domain,
+ &FN(MULTI(BASE),intersect_domain_aligned));
+}
+
+/* Intersect the parameter domain of "multi" with "domain".
+ *
+ * The parameters of "multi" and "domain" are assumed to have been aligned.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_params_aligned)(
+ __isl_take MULTI(BASE) *multi, __isl_take isl_set *domain)
+{
+ return FN(MULTI(BASE),intersect_aligned)(multi, domain,
+ &FN(EL,intersect_params));
+}
+
+/* Intersect the parameter domain of "multi" with "domain".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_params)(
+ __isl_take MULTI(BASE) *multi, __isl_take isl_set *domain)
+{
+ return FN(MULTI(BASE),align_params_multi_set_and)(multi, domain,
+ &FN(MULTI(BASE),intersect_params_aligned));
+}
+#endif
+
__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),LIST(BASE))(
__isl_take isl_space *space, __isl_take LIST(EL) *list)
{
@@ -632,10 +848,42 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),drop_dims)(
return multi;
}
+/* Align the parameters of "multi1" and "multi2" (if needed) and call "fn".
+ */
+static __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params_multi_multi_and)(
+ __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
+ __isl_give MULTI(BASE) *(*fn)(__isl_take MULTI(BASE) *multi1,
+ __isl_take MULTI(BASE) *multi2))
+{
+ isl_ctx *ctx;
+
+ if (!multi1 || !multi2)
+ goto error;
+ if (isl_space_match(multi1->space, isl_dim_param,
+ multi2->space, isl_dim_param))
+ return fn(multi1, multi2);
+ ctx = FN(MULTI(BASE),get_ctx)(multi1);
+ if (!isl_space_has_named_params(multi1->space) ||
+ !isl_space_has_named_params(multi2->space))
+ isl_die(ctx, isl_error_invalid,
+ "unaligned unnamed parameters", goto error);
+ multi1 = FN(MULTI(BASE),align_params)(multi1,
+ FN(MULTI(BASE),get_space)(multi2));
+ multi2 = FN(MULTI(BASE),align_params)(multi2,
+ FN(MULTI(BASE),get_space)(multi1));
+ return fn(multi1, multi2);
+error:
+ FN(MULTI(BASE),free)(multi1);
+ FN(MULTI(BASE),free)(multi2);
+ return NULL;
+}
+
/* Given two MULTI(BASE)s A -> B and C -> D,
- * construct a MULTI(BASE) (A * C) -> (B, D).
+ * construct a MULTI(BASE) (A * C) -> [B -> D].
+ *
+ * The parameters are assumed to have been aligned.
*/
-__isl_give MULTI(BASE) *FN(MULTI(BASE),range_product)(
+static __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product_aligned)(
__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
{
int i, n1, n2;
@@ -672,6 +920,129 @@ error:
return NULL;
}
+/* Given two MULTI(BASE)s A -> B and C -> D,
+ * construct a MULTI(BASE) (A * C) -> [B -> D].
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),range_product)(
+ __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
+{
+ return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
+ &FN(MULTI(BASE),range_product_aligned));
+}
+
+/* Is the range of "multi" a wrapped relation?
+ */
+int FN(MULTI(BASE),range_is_wrapping)(__isl_keep MULTI(BASE) *multi)
+{
+ if (!multi)
+ return -1;
+ return isl_space_range_is_wrapping(multi->space);
+}
+
+/* Given a function A -> [B -> C], extract the function A -> B.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_domain)(
+ __isl_take MULTI(BASE) *multi)
+{
+ isl_space *space;
+ int total, keep;
+
+ if (!multi)
+ return NULL;
+ if (!isl_space_range_is_wrapping(multi->space))
+ isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+ "range is not a product",
+ return FN(MULTI(BASE),free)(multi));
+
+ space = FN(MULTI(BASE),get_space)(multi);
+ total = isl_space_dim(space, isl_dim_out);
+ space = isl_space_range_factor_domain(space);
+ keep = isl_space_dim(space, isl_dim_out);
+ multi = FN(MULTI(BASE),drop_dims)(multi,
+ isl_dim_out, keep, total - keep);
+ multi = FN(MULTI(BASE),reset_space)(multi, space);
+
+ return multi;
+}
+
+/* Given a function A -> [B -> C], extract the function A -> C.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_range)(
+ __isl_take MULTI(BASE) *multi)
+{
+ isl_space *space;
+ int total, keep;
+
+ if (!multi)
+ return NULL;
+ if (!isl_space_range_is_wrapping(multi->space))
+ isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+ "range is not a product",
+ return FN(MULTI(BASE),free)(multi));
+
+ space = FN(MULTI(BASE),get_space)(multi);
+ total = isl_space_dim(space, isl_dim_out);
+ space = isl_space_range_factor_range(space);
+ keep = isl_space_dim(space, isl_dim_out);
+ multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_out, 0, total - keep);
+ multi = FN(MULTI(BASE),reset_space)(multi, space);
+
+ return multi;
+}
+
+/* Given two MULTI(BASE)s A -> B and C -> D,
+ * construct a MULTI(BASE) [A -> C] -> [B -> D].
+ *
+ * The parameters are assumed to have been aligned.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),product_aligned)(
+ __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
+{
+ int i;
+ EL *el;
+ isl_space *space;
+ MULTI(BASE) *res;
+ int in1, in2, out1, out2;
+
+ in1 = FN(MULTI(BASE),dim)(multi1, isl_dim_in);
+ in2 = FN(MULTI(BASE),dim)(multi2, isl_dim_in);
+ out1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
+ out2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out);
+ space = isl_space_product(FN(MULTI(BASE),get_space)(multi1),
+ FN(MULTI(BASE),get_space)(multi2));
+ res = FN(MULTI(BASE),alloc)(isl_space_copy(space));
+ space = isl_space_domain(space);
+
+ for (i = 0; i < out1; ++i) {
+ el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
+ el = FN(EL,insert_dims)(el, isl_dim_in, in1, in2);
+ el = FN(EL,reset_domain_space)(el, isl_space_copy(space));
+ res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
+ }
+
+ for (i = 0; i < out2; ++i) {
+ el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
+ el = FN(EL,insert_dims)(el, isl_dim_in, 0, in1);
+ el = FN(EL,reset_domain_space)(el, isl_space_copy(space));
+ res = FN(FN(MULTI(BASE),set),BASE)(res, out1 + i, el);
+ }
+
+ isl_space_free(space);
+ FN(MULTI(BASE),free)(multi1);
+ FN(MULTI(BASE),free)(multi2);
+ return res;
+}
+
+/* Given two MULTI(BASE)s A -> B and C -> D,
+ * construct a MULTI(BASE) [A -> C] -> [B -> D].
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),product)(
+ __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
+{
+ return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
+ &FN(MULTI(BASE),product_aligned));
+}
+
__isl_give MULTI(BASE) *FN(MULTI(BASE),flatten_range)(
__isl_take MULTI(BASE) *multi)
{
@@ -693,7 +1064,7 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),flatten_range)(
}
/* Given two MULTI(BASE)s A -> B and C -> D,
- * construct a MULTI(BASE) (A * C) -> [B -> D].
+ * construct a MULTI(BASE) (A * C) -> (B, D).
*/
__isl_give MULTI(BASE) *FN(MULTI(BASE),flat_range_product)(
__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
@@ -909,3 +1280,167 @@ error:
isl_multi_val_free(mv);
return FN(MULTI(BASE),free)(multi);
}
+
+/* Divide the elements of "multi" by the corresponding element of "mv"
+ * and return the result.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_multi_val)(
+ __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
+{
+ int i;
+
+ if (!multi || !mv)
+ goto error;
+
+ if (!isl_space_tuple_match(multi->space, isl_dim_out,
+ mv->space, isl_dim_set))
+ isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
+ "spaces don't match", goto error);
+
+ multi = FN(MULTI(BASE),cow)(multi);
+ if (!multi)
+ return NULL;
+
+ for (i = 0; i < multi->n; ++i) {
+ isl_val *v;
+
+ v = isl_multi_val_get_val(mv, i);
+ multi->p[i] = FN(EL,scale_down_val)(multi->p[i], v);
+ if (!multi->p[i])
+ goto error;
+ }
+
+ isl_multi_val_free(mv);
+ return multi;
+error:
+ isl_multi_val_free(mv);
+ return FN(MULTI(BASE),free)(multi);
+}
+
+#ifndef NO_MOVE_DIMS
+/* Move the "n" dimensions of "src_type" starting at "src_pos" of "multi"
+ * to dimensions of "dst_type" at "dst_pos".
+ *
+ * We only support moving input dimensions to parameters and vice versa.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),move_dims)(__isl_take MULTI(BASE) *multi,
+ enum isl_dim_type dst_type, unsigned dst_pos,
+ enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+ int i;
+
+ if (!multi)
+ return NULL;
+
+ if (n == 0 &&
+ !isl_space_is_named_or_nested(multi->space, src_type) &&
+ !isl_space_is_named_or_nested(multi->space, dst_type))
+ return multi;
+
+ if (dst_type == isl_dim_out || src_type == isl_dim_out)
+ isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+ "cannot move output/set dimension",
+ return FN(MULTI(BASE),free)(multi));
+ if (dst_type == isl_dim_div || src_type == isl_dim_div)
+ isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+ "cannot move divs",
+ return FN(MULTI(BASE),free)(multi));
+ if (src_pos + n > isl_space_dim(multi->space, src_type))
+ isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+ "range out of bounds",
+ return FN(MULTI(BASE),free)(multi));
+ if (dst_type == src_type)
+ isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_unsupported,
+ "moving dims within the same type not supported",
+ return FN(MULTI(BASE),free)(multi));
+
+ multi = FN(MULTI(BASE),cow)(multi);
+ if (!multi)
+ return NULL;
+
+ multi->space = isl_space_move_dims(multi->space, dst_type, dst_pos,
+ src_type, src_pos, n);
+ if (!multi->space)
+ return FN(MULTI(BASE),free)(multi);
+
+ for (i = 0; i < multi->n; ++i) {
+ multi->p[i] = FN(EL,move_dims)(multi->p[i], dst_type, dst_pos,
+ src_type, src_pos, n);
+ if (!multi->p[i])
+ return FN(MULTI(BASE),free)(multi);
+ }
+
+ return multi;
+}
+#endif
+
+/* Convert a multiple expression defined over a parameter domain
+ * into one that is defined over a zero-dimensional set.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),from_range)(
+ __isl_take MULTI(BASE) *multi)
+{
+ isl_space *space;
+
+ if (!multi)
+ return NULL;
+ if (!isl_space_is_set(multi->space))
+ isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+ "not living in a set space",
+ return FN(MULTI(BASE),free)(multi));
+
+ space = FN(MULTI(BASE),get_space)(multi);
+ space = isl_space_from_range(space);
+ multi = FN(MULTI(BASE),reset_space)(multi, space);
+
+ return multi;
+}
+
+/* Are "multi1" and "multi2" obviously equal?
+ */
+int FN(MULTI(BASE),plain_is_equal)(__isl_keep MULTI(BASE) *multi1,
+ __isl_keep MULTI(BASE) *multi2)
+{
+ int i;
+ int equal;
+
+ if (!multi1 || !multi2)
+ return -1;
+ if (multi1->n != multi2->n)
+ return 0;
+ equal = isl_space_is_equal(multi1->space, multi2->space);
+ if (equal < 0 || !equal)
+ return equal;
+
+ for (i = 0; i < multi1->n; ++i) {
+ equal = FN(EL,plain_is_equal)(multi1->p[i], multi2->p[i]);
+ if (equal < 0 || !equal)
+ return equal;
+ }
+
+ return 1;
+}
+
+#ifndef NO_DOMAIN
+/* Return the shared domain of the elements of "multi".
+ */
+__isl_give isl_set *FN(MULTI(BASE),domain)(__isl_take MULTI(BASE) *multi)
+{
+ int i;
+ isl_set *dom;
+
+ if (!multi)
+ return NULL;
+
+ dom = isl_set_universe(FN(MULTI(BASE),get_domain_space)(multi));
+ for (i = 0; i < multi->n; ++i) {
+ isl_set *dom_i;
+
+ dom_i = FN(EL,domain)(FN(FN(MULTI(BASE),get),BASE)(multi, i));
+ dom = isl_set_intersect(dom, dom_i);
+ }
+
+ FN(MULTI(BASE),free)(multi);
+ return dom;
+}
+#endif