add isl_aff
authorSven Verdoolaege <skimo@kotnet.org>
Sat, 16 Apr 2011 14:23:57 +0000 (16:23 +0200)
committerSven Verdoolaege <skimo@kotnet.org>
Mon, 16 May 2011 16:05:39 +0000 (18:05 +0200)
Affine expressions will be used in a subsequent commit to specify
the objective function for an ILP problem, but they should hopefully
be more generally useful.

Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>
Makefile.am
doc/user.pod
include/isl/aff.h [new file with mode: 0644]
isl_aff.c [new file with mode: 0644]
isl_aff_private.h [new file with mode: 0644]
isl_output.c

index 9e66564..71e98d8 100644 (file)
@@ -34,6 +34,8 @@ INCLUDES = -I. -I$(srcdir) -I$(srcdir)/include -Iinclude/
 libisl_la_SOURCES = \
        $(ISL_PIPLIB) \
        $(GET_MEMORY_FUNCTIONS) \
+       isl_aff.c \
+       isl_aff_private.h \
        isl_affine_hull.c \
        isl_arg.c \
        isl_basis_reduction.h \
@@ -181,6 +183,7 @@ nodist_pkginclude_HEADERS = \
        include/isl/config.h \
        include/isl/stdint.h
 pkginclude_HEADERS = \
+       include/isl/aff.h \
        include/isl/arg.h \
        include/isl/blk.h \
        include/isl/constraint.h \
index a0b3547..a082991 100644 (file)
@@ -2016,6 +2016,77 @@ the original and the kernel (in that order) is the zero matrix.
 
        __isl_give isl_mat *isl_mat_right_kernel(__isl_take isl_mat *mat);
 
+=head2 Quasi Affine Expressions
+
+The zero quasi affine expression can be created using
+
+       __isl_give isl_aff *isl_aff_zero(
+               __isl_take isl_local_space *ls);
+
+Quasi affine expressions can be copied and free using
+
+       #include <isl/aff.h>
+       __isl_give isl_aff *isl_aff_copy(__isl_keep isl_aff *aff);
+       void *isl_aff_free(__isl_take isl_aff *aff);
+
+The expression can be inspected using
+
+       #include <isl/aff.h>
+       isl_ctx *isl_aff_get_ctx(__isl_keep isl_aff *aff);
+       int isl_aff_dim(__isl_keep isl_aff *aff,
+               enum isl_dim_type type);
+       __isl_give isl_local_space *isl_aff_get_local_space(
+               __isl_keep isl_aff *aff);
+       const char *isl_aff_get_dim_name(__isl_keep isl_aff *aff,
+               enum isl_dim_type type, unsigned pos);
+       int isl_aff_get_constant(__isl_keep isl_aff *aff,
+               isl_int *v);
+       int isl_aff_get_coefficient(__isl_keep isl_aff *aff,
+               enum isl_dim_type type, int pos, isl_int *v);
+       int isl_aff_get_denominator(__isl_keep isl_aff *aff,
+               isl_int *v);
+       __isl_give isl_div *isl_aff_get_div(
+               __isl_keep isl_aff *aff, int pos);
+
+It can be modified using
+
+       #include <isl/aff.h>
+       __isl_give isl_aff *isl_aff_set_constant(
+               __isl_take isl_aff *aff, isl_int v);
+       __isl_give isl_aff *isl_aff_set_constant_si(
+               __isl_take isl_aff *aff, int v);
+       __isl_give isl_aff *isl_aff_set_coefficient(
+               __isl_take isl_aff *aff,
+               enum isl_dim_type type, int pos, isl_int v);
+       __isl_give isl_aff *isl_aff_set_coefficient_si(
+               __isl_take isl_aff *aff,
+               enum isl_dim_type type, int pos, int v);
+       __isl_give isl_aff *isl_aff_set_denominator(
+               __isl_take isl_aff *aff, isl_int v);
+
+       __isl_give isl_aff *isl_aff_add_constant(
+               __isl_take isl_aff *aff, isl_int v);
+       __isl_give isl_aff *isl_aff_add_coefficient_si(
+               __isl_take isl_aff *aff,
+               enum isl_dim_type type, int pos, int v);
+
+Note that the C<set_constant> and C<set_coefficient> functions
+set the I<numerator> of the constant or coefficient, while
+C<add_constant> and C<add_coefficient> add an integer value to
+the possibly rational constant or coefficient.
+
+Operations include
+
+       #include <isl/aff.h>
+       __isl_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff);
+       __isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff);
+
+An expression can be printed using
+
+       #include <isl/aff.h>
+       __isl_give isl_printer *isl_printer_print_aff(
+               __isl_take isl_printer *p, __isl_keep isl_aff *aff);
+
 =head2 Points
 
 Points are elements of a set.  They can be used to construct
diff --git a/include/isl/aff.h b/include/isl/aff.h
new file mode 100644 (file)
index 0000000..398b96e
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef ISL_AFF_H
+#define ISL_AFF_H
+
+#include <isl/div.h>
+#include <isl/local_space.h>
+#include <isl/printer.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_aff;
+typedef struct isl_aff isl_aff;
+
+__isl_give isl_aff *isl_aff_zero(__isl_take isl_local_space *ls);
+
+__isl_give isl_aff *isl_aff_copy(__isl_keep isl_aff *aff);
+void *isl_aff_free(__isl_take isl_aff *aff);
+
+isl_ctx *isl_aff_get_ctx(__isl_keep isl_aff *aff);
+
+int isl_aff_dim(__isl_keep isl_aff *aff, enum isl_dim_type type);
+
+__isl_give isl_local_space *isl_aff_get_local_space(__isl_keep isl_aff *aff);
+
+const char *isl_aff_get_dim_name(__isl_keep isl_aff *aff,
+       enum isl_dim_type type, unsigned pos);
+int isl_aff_get_constant(__isl_keep isl_aff *aff, isl_int *v);
+int isl_aff_get_coefficient(__isl_keep isl_aff *aff,
+       enum isl_dim_type type, int pos, isl_int *v);
+int isl_aff_get_denominator(__isl_keep isl_aff *aff, isl_int *v);
+__isl_give isl_aff *isl_aff_set_constant(__isl_take isl_aff *aff, isl_int v);
+__isl_give isl_aff *isl_aff_set_constant_si(__isl_take isl_aff *aff, int v);
+__isl_give isl_aff *isl_aff_set_coefficient(__isl_take isl_aff *aff,
+       enum isl_dim_type type, int pos, isl_int v);
+__isl_give isl_aff *isl_aff_set_coefficient_si(__isl_take isl_aff *aff,
+       enum isl_dim_type type, int pos, int v);
+__isl_give isl_aff *isl_aff_set_denominator(__isl_take isl_aff *aff, isl_int v);
+__isl_give isl_aff *isl_aff_add_constant(__isl_take isl_aff *aff, isl_int v);
+__isl_give isl_aff *isl_aff_add_coefficient_si(__isl_take isl_aff *aff,
+       enum isl_dim_type type, int pos, int v);
+
+__isl_give isl_div *isl_aff_get_div(__isl_keep isl_aff *aff, int pos);
+
+__isl_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff);
+__isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff);
+
+__isl_give isl_printer *isl_printer_print_aff(__isl_take isl_printer *p,
+       __isl_keep isl_aff *aff);
+void isl_aff_dump(__isl_keep isl_aff *aff);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/isl_aff.c b/isl_aff.c
new file mode 100644 (file)
index 0000000..26937b5
--- /dev/null
+++ b/isl_aff.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright 2011      INRIA Saclay
+ *
+ * Use of this software is governed by the GNU LGPLv2.1 license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ */
+
+#include <isl_aff_private.h>
+#include <isl_local_space_private.h>
+#include <isl/seq.h>
+
+__isl_give isl_aff *isl_aff_alloc_vec(__isl_take isl_local_space *ls,
+       __isl_take isl_vec *v)
+{
+       isl_aff *aff;
+
+       if (!ls || !v)
+               goto error;
+
+       aff = isl_calloc_type(v->ctx, struct isl_aff);
+       if (!aff)
+               goto error;
+
+       aff->ref = 1;
+       aff->ls = ls;
+       aff->v = v;
+
+       return aff;
+error:
+       isl_local_space_free(ls);
+       isl_vec_free(v);
+       return NULL;
+}
+
+__isl_give isl_aff *isl_aff_alloc(__isl_take isl_local_space *ls)
+{
+       isl_ctx *ctx;
+       isl_vec *v;
+       unsigned total;
+
+       if (!ls)
+               return NULL;
+
+       ctx = isl_local_space_get_ctx(ls);
+       total = isl_local_space_dim(ls, isl_dim_all);
+       v = isl_vec_alloc(ctx, 1 + 1 + total);
+       return isl_aff_alloc_vec(ls, v);
+}
+
+__isl_give isl_aff *isl_aff_zero(__isl_take isl_local_space *ls)
+{
+       isl_aff *aff;
+
+       aff = isl_aff_alloc(ls);
+       if (!aff)
+               return NULL;
+
+       isl_int_set_si(aff->v->el[0], 1);
+       isl_seq_clr(aff->v->el + 1, aff->v->size - 1);
+
+       return aff;
+}
+
+__isl_give isl_aff *isl_aff_copy(__isl_keep isl_aff *aff)
+{
+       if (!aff)
+               return NULL;
+
+       aff->ref++;
+       return aff;
+}
+
+__isl_give isl_aff *isl_aff_dup(__isl_keep isl_aff *aff)
+{
+       if (!aff)
+               return NULL;
+
+       return isl_aff_alloc_vec(isl_local_space_copy(aff->ls),
+                                isl_vec_copy(aff->v));
+}
+
+__isl_give isl_aff *isl_aff_cow(__isl_take isl_aff *aff)
+{
+       if (!aff)
+               return NULL;
+
+       if (aff->ref == 1)
+               return aff;
+       aff->ref--;
+       return isl_aff_dup(aff);
+}
+
+void *isl_aff_free(__isl_take isl_aff *aff)
+{
+       if (!aff)
+               return NULL;
+
+       if (--aff->ref > 0)
+               return NULL;
+
+       isl_local_space_free(aff->ls);
+       isl_vec_free(aff->v);
+
+       free(aff);
+
+       return NULL;
+}
+
+isl_ctx *isl_aff_get_ctx(__isl_keep isl_aff *aff)
+{
+       return aff ? isl_local_space_get_ctx(aff->ls) : NULL;
+}
+
+int isl_aff_dim(__isl_keep isl_aff *aff, enum isl_dim_type type)
+{
+       return aff ? isl_local_space_dim(aff->ls, type) : 0;
+}
+
+__isl_give isl_local_space *isl_aff_get_local_space(__isl_keep isl_aff *aff)
+{
+       return aff ? isl_local_space_copy(aff->ls) : NULL;
+}
+
+const char *isl_aff_get_dim_name(__isl_keep isl_aff *aff,
+       enum isl_dim_type type, unsigned pos)
+{
+       return aff ? isl_local_space_get_dim_name(aff->ls, type, pos) : 0;
+}
+
+int isl_aff_get_denominator(__isl_keep isl_aff *aff, isl_int *v)
+{
+       if (!aff)
+               return -1;
+       isl_int_set(*v, aff->v->el[0]);
+       return 0;
+}
+
+int isl_aff_get_constant(__isl_keep isl_aff *aff, isl_int *v)
+{
+       if (!aff)
+               return -1;
+       isl_int_set(*v, aff->v->el[1]);
+       return 0;
+}
+
+int isl_aff_get_coefficient(__isl_keep isl_aff *aff,
+       enum isl_dim_type type, int pos, isl_int *v)
+{
+       if (!aff)
+               return -1;
+
+       if (pos >= isl_local_space_dim(aff->ls, type))
+               isl_die(aff->v->ctx, isl_error_invalid,
+                       "position out of bounds", return -1);
+
+       pos += isl_local_space_offset(aff->ls, type);
+       isl_int_set(*v, aff->v->el[1 + pos]);
+
+       return 0;
+}
+
+__isl_give isl_aff *isl_aff_set_denominator(__isl_take isl_aff *aff, isl_int v)
+{
+       aff = isl_aff_cow(aff);
+       if (!aff)
+               return NULL;
+
+       aff->v = isl_vec_cow(aff->v);
+       if (!aff->v)
+               return isl_aff_free(aff);
+
+       isl_int_set(aff->v->el[0], v);
+
+       return aff;
+}
+
+__isl_give isl_aff *isl_aff_set_constant(__isl_take isl_aff *aff, isl_int v)
+{
+       aff = isl_aff_cow(aff);
+       if (!aff)
+               return NULL;
+
+       aff->v = isl_vec_cow(aff->v);
+       if (!aff->v)
+               return isl_aff_free(aff);
+
+       isl_int_set(aff->v->el[1], v);
+
+       return aff;
+}
+
+__isl_give isl_aff *isl_aff_add_constant(__isl_take isl_aff *aff, isl_int v)
+{
+       if (isl_int_is_zero(v))
+               return aff;
+
+       aff = isl_aff_cow(aff);
+       if (!aff)
+               return NULL;
+
+       aff->v = isl_vec_cow(aff->v);
+       if (!aff->v)
+               return isl_aff_free(aff);
+
+       isl_int_addmul(aff->v->el[1], aff->v->el[0], v);
+
+       return aff;
+}
+
+__isl_give isl_aff *isl_aff_set_constant_si(__isl_take isl_aff *aff, int v)
+{
+       aff = isl_aff_cow(aff);
+       if (!aff)
+               return NULL;
+
+       aff->v = isl_vec_cow(aff->v);
+       if (!aff->v)
+               return isl_aff_free(aff);
+
+       isl_int_set_si(aff->v->el[1], v);
+
+       return aff;
+}
+
+__isl_give isl_aff *isl_aff_set_coefficient(__isl_take isl_aff *aff,
+       enum isl_dim_type type, int pos, isl_int v)
+{
+       if (!aff)
+               return NULL;
+
+       if (pos >= isl_local_space_dim(aff->ls, type))
+               isl_die(aff->v->ctx, isl_error_invalid,
+                       "position out of bounds", return isl_aff_free(aff));
+
+       aff = isl_aff_cow(aff);
+       if (!aff)
+               return NULL;
+
+       aff->v = isl_vec_cow(aff->v);
+       if (!aff->v)
+               return isl_aff_free(aff);
+
+       pos += isl_local_space_offset(aff->ls, type);
+       isl_int_set(aff->v->el[1 + pos], v);
+
+       return aff;
+}
+
+__isl_give isl_aff *isl_aff_set_coefficient_si(__isl_take isl_aff *aff,
+       enum isl_dim_type type, int pos, int v)
+{
+       if (!aff)
+               return NULL;
+
+       if (pos >= isl_local_space_dim(aff->ls, type))
+               isl_die(aff->v->ctx, isl_error_invalid,
+                       "position out of bounds", return isl_aff_free(aff));
+
+       aff = isl_aff_cow(aff);
+       if (!aff)
+               return NULL;
+
+       aff->v = isl_vec_cow(aff->v);
+       if (!aff->v)
+               return isl_aff_free(aff);
+
+       pos += isl_local_space_offset(aff->ls, type);
+       isl_int_set_si(aff->v->el[1 + pos], v);
+
+       return aff;
+}
+
+__isl_give isl_aff *isl_aff_add_coefficient(__isl_take isl_aff *aff,
+       enum isl_dim_type type, int pos, isl_int v)
+{
+       if (!aff)
+               return NULL;
+
+       if (pos >= isl_local_space_dim(aff->ls, type))
+               isl_die(aff->v->ctx, isl_error_invalid,
+                       "position out of bounds", return isl_aff_free(aff));
+
+       aff = isl_aff_cow(aff);
+       if (!aff)
+               return NULL;
+
+       aff->v = isl_vec_cow(aff->v);
+       if (!aff->v)
+               return isl_aff_free(aff);
+
+       pos += isl_local_space_offset(aff->ls, type);
+       isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v);
+
+       return aff;
+}
+
+__isl_give isl_aff *isl_aff_add_coefficient_si(__isl_take isl_aff *aff,
+       enum isl_dim_type type, int pos, int v)
+{
+       isl_int t;
+
+       isl_int_init(t);
+       isl_int_set_si(t, v);
+       aff = isl_aff_add_coefficient(aff, type, pos, t);
+       isl_int_clear(t);
+
+       return aff;
+}
+
+__isl_give isl_div *isl_aff_get_div(__isl_keep isl_aff *aff, int pos)
+{
+       if (!aff)
+               return NULL;
+
+       return isl_local_space_get_div(aff->ls, pos);
+}
+
+__isl_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff)
+{
+       aff = isl_aff_cow(aff);
+       if (!aff)
+               return NULL;
+       aff->v = isl_vec_cow(aff->v);
+       if (!aff->v)
+               return isl_aff_free(aff);
+
+       isl_seq_neg(aff->v->el + 1, aff->v->el + 1, aff->v->size - 1);
+
+       return aff;
+}
+
+/* Given f, return ceil(f).
+ * If f is an integer expression, then just return f.
+ * Otherwise, create a new div d = [-f] and return the expression -d.
+ */
+__isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff)
+{
+       int size;
+       isl_ctx *ctx;
+
+       if (!aff)
+               return NULL;
+
+       if (isl_int_is_one(aff->v->el[0]))
+               return aff;
+
+       aff = isl_aff_cow(aff);
+       if (!aff)
+               return NULL;
+
+       isl_seq_neg(aff->v->el + 1, aff->v->el + 1, aff->v->size - 1);
+       aff->ls = isl_local_space_add_div(aff->ls, isl_vec_copy(aff->v));
+       if (!aff->ls)
+               goto error;
+
+       ctx = isl_aff_get_ctx(aff);
+       size = aff->v->size;
+       isl_vec_free(aff->v);
+       aff->v = isl_vec_alloc(ctx, size + 1);
+       aff->v = isl_vec_clr(aff->v);
+       if (!aff->v)
+               goto error;
+       isl_int_set_si(aff->v->el[0], 1);
+       isl_int_set_si(aff->v->el[size], -1);
+
+       return aff;
+error:
+       isl_aff_free(aff);
+       return NULL;
+}
+
+/* Apply the expansion computed by isl_merge_divs.
+ * The expansion itself is given by "exp" while the resulting
+ * list of divs is given by "div".
+ */
+__isl_give isl_aff *isl_aff_expand_divs( __isl_take isl_aff *aff,
+       __isl_take isl_mat *div, int *exp)
+{
+       int i, j;
+       int old_n_div;
+       int new_n_div;
+       int offset;
+
+       aff = isl_aff_cow(aff);
+       if (!aff || !div)
+               goto error;
+
+       old_n_div = isl_local_space_dim(aff->ls, isl_dim_div);
+       new_n_div = isl_mat_rows(div);
+       if (new_n_div < old_n_div)
+               isl_die(isl_mat_get_ctx(div), isl_error_invalid,
+                       "not an expansion", goto error);
+
+       aff->v = isl_vec_extend(aff->v, aff->v->size + new_n_div - old_n_div);
+       if (!aff->v)
+               goto error;
+
+       offset = 1 + isl_local_space_offset(aff->ls, isl_dim_div);
+       j = old_n_div - 1;
+       for (i = new_n_div - 1; i >= 0; --i) {
+               if (j >= 0 && exp[j] == i) {
+                       if (i != j)
+                               isl_int_swap(aff->v->el[offset + i],
+                                            aff->v->el[offset + j]);
+                       j--;
+               } else
+                       isl_int_set_si(aff->v->el[offset + j], 0);
+       }
+
+       aff->ls = isl_local_space_replace_divs(aff->ls, isl_mat_copy(div));
+       if (!aff->ls)
+               goto error;
+       isl_mat_free(div);
+       return aff;
+error:
+       isl_aff_free(aff);
+       isl_mat_free(div);
+       return NULL;
+}
diff --git a/isl_aff_private.h b/isl_aff_private.h
new file mode 100644 (file)
index 0000000..e887eb3
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef ISL_AFF_PRIVATE_H
+#define ISL_AFF_PRIVATE_H
+
+#include <isl/aff.h>
+#include <isl/vec.h>
+#include <isl/mat.h>
+#include <isl/local_space.h>
+
+struct isl_aff {
+       int ref;
+
+       isl_local_space *ls;
+       isl_vec         *v;
+};
+
+__isl_give isl_aff *isl_aff_alloc(__isl_take isl_local_space *ls);
+
+__isl_give isl_aff *isl_aff_expand_divs( __isl_take isl_aff *aff,
+       __isl_take isl_mat *div, int *exp);
+
+#endif
index f736745..fa892db 100644 (file)
@@ -23,6 +23,7 @@
 #include <isl/union_map.h>
 #include <isl/constraint.h>
 #include <isl_local_space_private.h>
+#include <isl_aff_private.h>
 
 static const char *s_to[2] = { " -> ", " \\to " };
 static const char *s_and[2] = { " and ", " \\wedge " };
@@ -2175,3 +2176,48 @@ void isl_local_space_dump(__isl_keep isl_local_space *ls)
 
        isl_printer_free(printer);
 }
+
+__isl_give isl_printer *isl_printer_print_aff(__isl_take isl_printer *p,
+       __isl_keep isl_aff *aff)
+{
+       unsigned total;
+
+       if (!aff)
+               goto error;
+
+       total = isl_local_space_dim(aff->ls, isl_dim_all);
+       if (isl_local_space_dim(aff->ls, isl_dim_param) > 0) {
+               p = print_tuple(aff->ls->dim, p, isl_dim_param, 0, 0, NULL);
+               p = isl_printer_print_str(p, " -> ");
+       }
+       p = isl_printer_print_str(p, "{ ");
+       p = print_tuple(aff->ls->dim, p, isl_dim_set, 1, 0, NULL);
+       p = isl_printer_print_str(p, " -> [");
+       if (!isl_int_is_one(aff->v->el[0]))
+               p = isl_printer_print_str(p, "(");
+       p = print_affine_of_len(aff->ls->dim, aff->ls->div, p,
+                               aff->v->el + 1, 1 + total, 1);
+       if (!isl_int_is_one(aff->v->el[0])) {
+               p = isl_printer_print_str(p, ")/");
+               p = isl_printer_print_isl_int(p, aff->v->el[0]);
+       }
+       p = isl_printer_print_str(p, "] }");
+       return p;
+error:
+       isl_printer_free(p);
+       return NULL;
+}
+
+void isl_aff_dump(__isl_keep isl_aff *aff)
+{
+       isl_printer *printer;
+
+       if (!aff)
+               return;
+
+       printer = isl_printer_to_file(isl_aff_get_ctx(aff), stderr);
+       printer = isl_printer_print_aff(printer, aff);
+       printer = isl_printer_end_line(printer);
+
+       isl_printer_free(printer);
+}