isl_aff.c: document isl_aff_normalize
[platform/upstream/isl.git] / isl_aff.c
index 03516b1..e47cad9 100644 (file)
--- a/isl_aff.c
+++ b/isl_aff.c
@@ -3,7 +3,7 @@
  * Copyright 2011      Sven Verdoolaege
  * Copyright 2012      Ecole Normale Superieure
  *
- * 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,
@@ -648,6 +648,12 @@ __isl_give isl_aff *isl_aff_remove_unused_divs( __isl_take isl_aff *aff)
        return aff;
 }
 
+/* Normalize the representation of "aff".
+ *
+ * This function should only be called of "new" isl_affs, i.e.,
+ * with only a single reference.  We therefore do not need to
+ * worry about affecting other instances.
+ */
 __isl_give isl_aff *isl_aff_normalize(__isl_take isl_aff *aff)
 {
        if (!aff)
@@ -939,6 +945,11 @@ __isl_give isl_aff *isl_aff_scale_down(__isl_take isl_aff *aff, isl_int f)
        aff = isl_aff_cow(aff);
        if (!aff)
                return NULL;
+
+       if (isl_int_is_zero(f))
+               isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+                       "cannot scale down by zero", return isl_aff_free(aff));
+
        aff->v = isl_vec_cow(aff->v);
        if (!aff->v)
                return isl_aff_free(aff);
@@ -2264,6 +2275,47 @@ error:
        return NULL;
 }
 
+/* Given two multi-affine expressions A -> B and C -> D,
+ * construct a multi-affine expression [A -> C] -> [B -> D].
+ */
+__isl_give isl_multi_aff *isl_multi_aff_product(
+       __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2)
+{
+       int i;
+       isl_aff *aff;
+       isl_space *space;
+       isl_multi_aff *res;
+       int in1, in2, out1, out2;
+
+       in1 = isl_multi_aff_dim(ma1, isl_dim_in);
+       in2 = isl_multi_aff_dim(ma2, isl_dim_in);
+       out1 = isl_multi_aff_dim(ma1, isl_dim_out);
+       out2 = isl_multi_aff_dim(ma2, isl_dim_out);
+       space = isl_space_product(isl_multi_aff_get_space(ma1),
+                                 isl_multi_aff_get_space(ma2));
+       res = isl_multi_aff_alloc(isl_space_copy(space));
+       space = isl_space_domain(space);
+
+       for (i = 0; i < out1; ++i) {
+               aff = isl_multi_aff_get_aff(ma1, i);
+               aff = isl_aff_insert_dims(aff, isl_dim_in, in1, in2);
+               aff = isl_aff_reset_domain_space(aff, isl_space_copy(space));
+               res = isl_multi_aff_set_aff(res, i, aff);
+       }
+
+       for (i = 0; i < out2; ++i) {
+               aff = isl_multi_aff_get_aff(ma2, i);
+               aff = isl_aff_insert_dims(aff, isl_dim_in, 0, in1);
+               aff = isl_aff_reset_domain_space(aff, isl_space_copy(space));
+               res = isl_multi_aff_set_aff(res, out1 + i, aff);
+       }
+
+       isl_space_free(space);
+       isl_multi_aff_free(ma1);
+       isl_multi_aff_free(ma2);
+       return res;
+}
+
 /* Exploit the equalities in "eq" to simplify the affine expressions.
  */
 static __isl_give isl_multi_aff *isl_multi_aff_substitute_equalities(
@@ -2471,6 +2523,158 @@ __isl_give isl_set *isl_multi_aff_lex_ge_set(__isl_take isl_multi_aff *ma1,
 
 #include <isl_union_templ.c>
 
+/* Given a function "cmp" that returns the set of elements where
+ * "ma1" is "better" than "ma2", return the intersection of this
+ * set with "dom1" and "dom2".
+ */
+static __isl_give isl_set *shared_and_better(__isl_keep isl_set *dom1,
+       __isl_keep isl_set *dom2, __isl_keep isl_multi_aff *ma1,
+       __isl_keep isl_multi_aff *ma2,
+       __isl_give isl_set *(*cmp)(__isl_take isl_multi_aff *ma1,
+                                   __isl_take isl_multi_aff *ma2))
+{
+       isl_set *common;
+       isl_set *better;
+       int is_empty;
+
+       common = isl_set_intersect(isl_set_copy(dom1), isl_set_copy(dom2));
+       is_empty = isl_set_plain_is_empty(common);
+       if (is_empty >= 0 && is_empty)
+               return common;
+       if (is_empty < 0)
+               return isl_set_free(common);
+       better = cmp(isl_multi_aff_copy(ma1), isl_multi_aff_copy(ma2));
+       better = isl_set_intersect(common, better);
+
+       return better;
+}
+
+/* Given a function "cmp" that returns the set of elements where
+ * "ma1" is "better" than "ma2", return a piecewise multi affine
+ * expression defined on the union of the definition domains
+ * of "pma1" and "pma2" that maps to the "best" of "pma1" and
+ * "pma2" on each cell.  If only one of the two input functions
+ * is defined on a given cell, then it is considered the best.
+ */
+static __isl_give isl_pw_multi_aff *pw_multi_aff_union_opt(
+       __isl_take isl_pw_multi_aff *pma1,
+       __isl_take isl_pw_multi_aff *pma2,
+       __isl_give isl_set *(*cmp)(__isl_take isl_multi_aff *ma1,
+                                   __isl_take isl_multi_aff *ma2))
+{
+       int i, j, n;
+       isl_pw_multi_aff *res = NULL;
+       isl_ctx *ctx;
+       isl_set *set = NULL;
+
+       if (!pma1 || !pma2)
+               goto error;
+
+       ctx = isl_space_get_ctx(pma1->dim);
+       if (!isl_space_is_equal(pma1->dim, pma2->dim))
+               isl_die(ctx, isl_error_invalid,
+                       "arguments should live in the same space", goto error);
+
+       if (isl_pw_multi_aff_is_empty(pma1)) {
+               isl_pw_multi_aff_free(pma1);
+               return pma2;
+       }
+
+       if (isl_pw_multi_aff_is_empty(pma2)) {
+               isl_pw_multi_aff_free(pma2);
+               return pma1;
+       }
+
+       n = 2 * (pma1->n + 1) * (pma2->n + 1);
+       res = isl_pw_multi_aff_alloc_size(isl_space_copy(pma1->dim), n);
+
+       for (i = 0; i < pma1->n; ++i) {
+               set = isl_set_copy(pma1->p[i].set);
+               for (j = 0; j < pma2->n; ++j) {
+                       isl_set *better;
+                       int is_empty;
+
+                       better = shared_and_better(pma2->p[j].set,
+                                       pma1->p[i].set, pma2->p[j].maff,
+                                       pma1->p[i].maff, cmp);
+                       is_empty = isl_set_plain_is_empty(better);
+                       if (is_empty < 0 || is_empty) {
+                               isl_set_free(better);
+                               if (is_empty < 0)
+                                       goto error;
+                               continue;
+                       }
+                       set = isl_set_subtract(set, isl_set_copy(better));
+
+                       res = isl_pw_multi_aff_add_piece(res, better,
+                                       isl_multi_aff_copy(pma2->p[j].maff));
+               }
+               res = isl_pw_multi_aff_add_piece(res, set,
+                                       isl_multi_aff_copy(pma1->p[i].maff));
+       }
+
+       for (j = 0; j < pma2->n; ++j) {
+               set = isl_set_copy(pma2->p[j].set);
+               for (i = 0; i < pma1->n; ++i)
+                       set = isl_set_subtract(set,
+                                       isl_set_copy(pma1->p[i].set));
+               res = isl_pw_multi_aff_add_piece(res, set,
+                                       isl_multi_aff_copy(pma2->p[j].maff));
+       }
+
+       isl_pw_multi_aff_free(pma1);
+       isl_pw_multi_aff_free(pma2);
+
+       return res;
+error:
+       isl_pw_multi_aff_free(pma1);
+       isl_pw_multi_aff_free(pma2);
+       isl_set_free(set);
+       return isl_pw_multi_aff_free(res);
+}
+
+static __isl_give isl_pw_multi_aff *pw_multi_aff_union_lexmax(
+       __isl_take isl_pw_multi_aff *pma1,
+       __isl_take isl_pw_multi_aff *pma2)
+{
+       return pw_multi_aff_union_opt(pma1, pma2, &isl_multi_aff_lex_ge_set);
+}
+
+/* Given two piecewise multi affine expressions, return a piecewise
+ * multi-affine expression defined on the union of the definition domains
+ * of the inputs that is equal to the lexicographic maximum of the two
+ * inputs on each cell.  If only one of the two inputs is defined on
+ * a given cell, then it is considered to be the maximum.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmax(
+       __isl_take isl_pw_multi_aff *pma1,
+       __isl_take isl_pw_multi_aff *pma2)
+{
+       return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
+                                                   &pw_multi_aff_union_lexmax);
+}
+
+static __isl_give isl_pw_multi_aff *pw_multi_aff_union_lexmin(
+       __isl_take isl_pw_multi_aff *pma1,
+       __isl_take isl_pw_multi_aff *pma2)
+{
+       return pw_multi_aff_union_opt(pma1, pma2, &isl_multi_aff_lex_le_set);
+}
+
+/* Given two piecewise multi affine expressions, return a piecewise
+ * multi-affine expression defined on the union of the definition domains
+ * of the inputs that is equal to the lexicographic minimum of the two
+ * inputs on each cell.  If only one of the two inputs is defined on
+ * a given cell, then it is considered to be the minimum.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmin(
+       __isl_take isl_pw_multi_aff *pma1,
+       __isl_take isl_pw_multi_aff *pma2)
+{
+       return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
+                                                   &pw_multi_aff_union_lexmin);
+}
+
 static __isl_give isl_pw_multi_aff *pw_multi_aff_add(
        __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
 {
@@ -2491,6 +2695,54 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add(
        return isl_pw_multi_aff_union_add_(pma1, pma2);
 }
 
+/* Given two piecewise multi-affine expressions A -> B and C -> D,
+ * construct a piecewise multi-affine expression [A -> C] -> [B -> D].
+ */
+static __isl_give isl_pw_multi_aff *pw_multi_aff_product(
+       __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+       int i, j, n;
+       isl_space *space;
+       isl_pw_multi_aff *res;
+
+       if (!pma1 || !pma2)
+               goto error;
+
+       n = pma1->n * pma2->n;
+       space = isl_space_product(isl_space_copy(pma1->dim),
+                                 isl_space_copy(pma2->dim));
+       res = isl_pw_multi_aff_alloc_size(space, n);
+
+       for (i = 0; i < pma1->n; ++i) {
+               for (j = 0; j < pma2->n; ++j) {
+                       isl_set *domain;
+                       isl_multi_aff *ma;
+
+                       domain = isl_set_product(isl_set_copy(pma1->p[i].set),
+                                                isl_set_copy(pma2->p[j].set));
+                       ma = isl_multi_aff_product(
+                                       isl_multi_aff_copy(pma1->p[i].maff),
+                                       isl_multi_aff_copy(pma2->p[i].maff));
+                       res = isl_pw_multi_aff_add_piece(res, domain, ma);
+               }
+       }
+
+       isl_pw_multi_aff_free(pma1);
+       isl_pw_multi_aff_free(pma2);
+       return res;
+error:
+       isl_pw_multi_aff_free(pma1);
+       isl_pw_multi_aff_free(pma2);
+       return NULL;
+}
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_product(
+       __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+       return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
+                                               &pw_multi_aff_product);
+}
+
 /* Construct a map mapping the domain of the piecewise multi-affine expression
  * to its range, with each dimension in the range equated to the
  * corresponding affine expression on its cell.
@@ -2733,7 +2985,7 @@ __isl_give isl_pw_aff *isl_set_indicator_function(__isl_take isl_set *set)
  *
  * The result is
  *
- *     floor((a f + d g')/(m d))
+ *     (a f + d g')/(m d)
  *
  * where g' is the result of plugging in "subs" in each of the integer
  * divisions in g.