add isl_union_pw_multi_aff_scale_vec
[platform/upstream/isl.git] / isl_aff.c
index e9d7286..6ff07ad 100644 (file)
--- a/isl_aff.c
+++ b/isl_aff.c
@@ -1,7 +1,7 @@
 /*
  * Copyright 2011      INRIA Saclay
  * 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
  *
@@ -1214,6 +1214,11 @@ __isl_give isl_aff *isl_aff_scale(__isl_take isl_aff *aff, isl_int f)
        if (!aff->v)
                return isl_aff_free(aff);
 
+       if (isl_int_is_pos(f) && isl_int_is_divisible_by(aff->v->el[0], f)) {
+               isl_int_divexact(aff->v->el[0], aff->v->el[0], f);
+               return aff;
+       }
+
        isl_int_init(gcd);
        isl_int_gcd(gcd, aff->v->el[0], f);
        isl_int_divexact(aff->v->el[0], aff->v->el[0], gcd);
@@ -2672,31 +2677,15 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_identity(
 __isl_give isl_multi_aff *isl_multi_aff_add(__isl_take isl_multi_aff *maff1,
        __isl_take isl_multi_aff *maff2)
 {
-       int i;
-       isl_ctx *ctx;
-
-       maff1 = isl_multi_aff_cow(maff1);
-       if (!maff1 || !maff2)
-               goto error;
-
-       ctx = isl_multi_aff_get_ctx(maff1);
-       if (!isl_space_is_equal(maff1->space, maff2->space))
-               isl_die(ctx, isl_error_invalid,
-                       "spaces don't match", goto error);
-
-       for (i = 0; i < maff1->n; ++i) {
-               maff1->p[i] = isl_aff_add(maff1->p[i],
-                                           isl_aff_copy(maff2->p[i]));
-               if (!maff1->p[i])
-                       goto error;
-       }
+       return isl_multi_aff_bin_op(maff1, maff2, &isl_aff_add);
+}
 
-       isl_multi_aff_free(maff2);
-       return maff1;
-error:
-       isl_multi_aff_free(maff1);
-       isl_multi_aff_free(maff2);
-       return NULL;
+/* Subtract "ma2" from "ma1" and return the result.
+ */
+__isl_give isl_multi_aff *isl_multi_aff_sub(__isl_take isl_multi_aff *ma1,
+       __isl_take isl_multi_aff *ma2)
+{
+       return isl_multi_aff_bin_op(ma1, ma2, &isl_aff_sub);
 }
 
 /* Given two multi-affine expressions A -> B and C -> D,
@@ -3057,6 +3046,22 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_add(
                                                &pw_multi_aff_add);
 }
 
+static __isl_give isl_pw_multi_aff *pw_multi_aff_sub(
+       __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+       return isl_pw_multi_aff_on_shared_domain(pma1, pma2,
+                                               &isl_multi_aff_sub);
+}
+
+/* Subtract "pma2" from "pma1" and return the result.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_sub(
+       __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_sub);
+}
+
 __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add(
        __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
 {
@@ -3761,6 +3766,51 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_set(__isl_take isl_set *set)
        return isl_pw_multi_aff_from_map(set);
 }
 
+/* Convert "map" into an isl_pw_multi_aff (if possible) and
+ * add it to *user.
+ */
+static int pw_multi_aff_from_map(__isl_take isl_map *map, void *user)
+{
+       isl_union_pw_multi_aff **upma = user;
+       isl_pw_multi_aff *pma;
+
+       pma = isl_pw_multi_aff_from_map(map);
+       *upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma);
+
+       return *upma ? 0 : -1;
+}
+
+/* Try and create an isl_union_pw_multi_aff that is equivalent
+ * to the given isl_union_map.
+ * The isl_union_map is required to be single-valued in each space.
+ * Otherwise, an error is produced.
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_map(
+       __isl_take isl_union_map *umap)
+{
+       isl_space *space;
+       isl_union_pw_multi_aff *upma;
+
+       space = isl_union_map_get_space(umap);
+       upma = isl_union_pw_multi_aff_empty(space);
+       if (isl_union_map_foreach_map(umap, &pw_multi_aff_from_map, &upma) < 0)
+               upma = isl_union_pw_multi_aff_free(upma);
+       isl_union_map_free(umap);
+
+       return upma;
+}
+
+/* Try and create an isl_union_pw_multi_aff that is equivalent
+ * to the given isl_union_set.
+ * The isl_union_set is required to be a singleton in each space.
+ * Otherwise, an error is produced.
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_set(
+       __isl_take isl_union_set *uset)
+{
+       return isl_union_pw_multi_aff_from_union_map(uset);
+}
+
 /* Return the piecewise affine expression "set ? 1 : 0".
  */
 __isl_give isl_pw_aff *isl_set_indicator_function(__isl_take isl_set *set)
@@ -4595,3 +4645,101 @@ error:
 #define BASE pw_aff
 
 #include <isl_multi_templ.c>
+
+/* Scale the first elements of "ma" by the corresponding elements of "vec".
+ */
+__isl_give isl_multi_aff *isl_multi_aff_scale_vec(__isl_take isl_multi_aff *ma,
+       __isl_take isl_vec *vec)
+{
+       int i, n;
+       isl_int v;
+
+       if (!ma || !vec)
+               goto error;
+
+       n = isl_multi_aff_dim(ma, isl_dim_out);
+       if (isl_vec_size(vec) < n)
+               n = isl_vec_size(vec);
+
+       isl_int_init(v);
+       for (i = 0; i < n; ++i) {
+               isl_aff *aff;
+
+               isl_vec_get_element(vec, i, &v);
+
+               aff = isl_multi_aff_get_aff(ma, i);
+               aff = isl_aff_scale(aff, v);
+               ma = isl_multi_aff_set_aff(ma, i, aff);
+       }
+       isl_int_clear(v);
+
+       isl_vec_free(vec);
+       return ma;
+error:
+       isl_vec_free(vec);
+       isl_multi_aff_free(ma);
+       return NULL;
+}
+
+/* Scale the first elements of "pma" by the corresponding elements of "vec".
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_vec(
+       __isl_take isl_pw_multi_aff *pma, __isl_take isl_vec *v)
+{
+       int i;
+
+       pma = isl_pw_multi_aff_cow(pma);
+       if (!pma || !v)
+               goto error;
+
+       for (i = 0; i < pma->n; ++i) {
+               pma->p[i].maff = isl_multi_aff_scale_vec(pma->p[i].maff,
+                                                       isl_vec_copy(v));
+               if (!pma->p[i].maff)
+                       goto error;
+       }
+
+       isl_vec_free(v);
+       return pma;
+error:
+       isl_vec_free(v);
+       isl_pw_multi_aff_free(pma);
+       return NULL;
+}
+
+/* This function is called for each entry of an isl_union_pw_multi_aff.
+ * Replace the entry by the result of applying isl_pw_multi_aff_scale_vec
+ * to the original entry with the isl_vec in "user" as extra argument.
+ */
+static int union_pw_multi_aff_scale_vec_entry(void **entry, void *user)
+{
+       isl_pw_multi_aff **pma = (isl_pw_multi_aff **) entry;
+       isl_vec *v = user;
+
+       *pma = isl_pw_multi_aff_scale_vec(*pma, isl_vec_copy(v));
+       if (!*pma)
+               return -1;
+
+       return 0;
+}
+
+/* Scale the first elements of "upma" by the corresponding elements of "vec".
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_scale_vec(
+       __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_vec *v)
+{
+       upma = isl_union_pw_multi_aff_cow(upma);
+       if (!upma || !v)
+               goto error;
+
+       if (isl_hash_table_foreach(upma->dim->ctx, &upma->table,
+                                  &union_pw_multi_aff_scale_vec_entry, v) < 0)
+               goto error;
+
+       isl_vec_free(v);
+       return upma;
+error:
+       isl_vec_free(v);
+       isl_union_pw_multi_aff_free(upma);
+       return NULL;
+}