Merge branch 'maint'
authorSven Verdoolaege <skimo@kotnet.org>
Fri, 20 May 2011 13:07:16 +0000 (15:07 +0200)
committerSven Verdoolaege <skimo@kotnet.org>
Fri, 20 May 2011 13:07:16 +0000 (15:07 +0200)
71 files changed:
AUTHORS
Makefile.am
basis_reduction_templ.c
configure.ac
doc/implementation.tex
doc/isl.bib
doc/manual.tex
doc/user.pod
include/isl/aff.h [new file with mode: 0644]
include/isl/constraint.h
include/isl/div.h
include/isl/ilp.h
include/isl/local_space.h [new file with mode: 0644]
include/isl/map.h
include/isl/mat.h
include/isl/options.h
include/isl/polynomial.h
include/isl/schedule.h [new file with mode: 0644]
include/isl/set.h
include/isl/union_map.h
include/isl/union_set.h
include/isl/vec.h
isl_aff.c [new file with mode: 0644]
isl_aff_private.h [new file with mode: 0644]
isl_affine_hull.c
isl_blk.c
isl_constraint.c
isl_convex_hull.c
isl_ctx.c
isl_ctx_private.h
isl_dim.c
isl_dim_map.c [new file with mode: 0644]
isl_dim_map.h [new file with mode: 0644]
isl_dim_private.h
isl_div.c
isl_div_private.h [new file with mode: 0644]
isl_equalities.c
isl_farkas.c [new file with mode: 0644]
isl_flow.c
isl_fold.c
isl_hmap_map_basic_set.c [new file with mode: 0644]
isl_hmap_map_basic_set.h [new file with mode: 0644]
isl_ilp.c
isl_local_space.c [new file with mode: 0644]
isl_local_space_private.h [new file with mode: 0644]
isl_map.c
isl_map_private.h
isl_map_simplify.c
isl_map_subtract.c
isl_mat.c
isl_mat_private.h
isl_morph.c
isl_options.c
isl_output.c
isl_polynomial.c
isl_polynomial_private.h
isl_pw_templ.c
isl_qsort.c [new file with mode: 0644]
isl_qsort.h [new file with mode: 0644]
isl_sample.c
isl_schedule.c [new file with mode: 0644]
isl_tab.c
isl_tab.h
isl_tab_pip.c
isl_test.c
isl_transitive_closure.c
isl_union_map.c
isl_vec.c
isl_vertices.c
pip.c
polytope_scan.c

diff --git a/AUTHORS b/AUTHORS
index e8d59e5..965ed11 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -15,3 +15,5 @@ isl was written by
            Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod
            91893 Orsay
            France
+
+The quicksort implementation was written by Douglas C. Schmidt.
index be7844e..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 \
@@ -50,18 +52,26 @@ libisl_la_SOURCES = \
        isl_ctx_private.h \
        isl_dim.c \
        isl_dim_private.h \
+       isl_dim_map.h \
+       isl_dim_map.c \
        isl_div.c \
+       isl_div_private.h \
        isl_equalities.c \
        isl_equalities.h \
        isl_factorization.c \
        isl_factorization.h \
+       isl_farkas.c \
        isl_flow.c \
        isl_fold.c \
        isl_gmp.c \
        isl_hash.c \
+       isl_hmap_map_basic_set.c \
+       isl_hmap_map_basic_set.h \
        isl_ilp.c \
        isl_input.c \
        isl_list.c \
+       isl_local_space_private.h \
+       isl_local_space.c \
        isl_lp.c \
        isl_lp_piplib.h \
        isl_map.c \
@@ -78,6 +88,8 @@ libisl_la_SOURCES = \
        isl_obj.c \
        isl_options.c \
        isl_output.c \
+       isl_qsort.c \
+       isl_qsort.h \
        isl_piplib.h \
        isl_point_private.h \
        isl_point.c \
@@ -93,6 +105,7 @@ libisl_la_SOURCES = \
        isl_sample.c \
        isl_scan.c \
        isl_scan.h \
+       isl_schedule.c \
        isl_stream.c \
        isl_seq.c \
        isl_tab.c \
@@ -120,7 +133,8 @@ libisl_la_LDFLAGS = -version-info @versioninfo@ \
 libisl_la_CPPFLAGS = $(INCLUDES) @PIPLIB_CPPFLAGS@ @GMP_CPPFLAGS@
 
 isl_test_CPPFLAGS = $(INCLUDES) @GMP_CPPFLAGS@
-isl_test_LDADD = libisl.la
+isl_test_LDFLAGS = @GMP_LDFLAGS@
+isl_test_LDADD = libisl.la -lgmp
 
 isl_polyhedron_sample_CPPFLAGS = $(INCLUDES) @GMP_CPPFLAGS@
 isl_polyhedron_sample_LDADD = libisl.la
@@ -128,17 +142,20 @@ isl_polyhedron_sample_SOURCES = \
        polyhedron_sample.c
 
 isl_pip_CPPFLAGS = $(INCLUDES) @GMP_CPPFLAGS@
-isl_pip_LDADD = libisl.la
+isl_pip_LDFLAGS = @GMP_LDFLAGS@
+isl_pip_LDADD = libisl.la -lgmp
 isl_pip_SOURCES = \
        pip.c
 
 isl_bound_CPPFLAGS = $(INCLUDES) @GMP_CPPFLAGS@
-isl_bound_LDADD = libisl.la
+isl_bound_LDFLAGS = @GMP_LDFLAGS@
+isl_bound_LDADD = libisl.la -lgmp
 isl_bound_SOURCES = \
        bound.c
 
 isl_polyhedron_minimize_CPPFLAGS = $(INCLUDES) @GMP_CPPFLAGS@
-isl_polyhedron_minimize_LDADD = libisl.la
+isl_polyhedron_minimize_LDFLAGS = @GMP_LDFLAGS@
+isl_polyhedron_minimize_LDADD = libisl.la -lgmp
 isl_polyhedron_minimize_SOURCES = \
        polyhedron_minimize.c
 
@@ -166,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 \
@@ -177,6 +195,7 @@ pkginclude_HEADERS = \
        include/isl/int.h \
        include/isl/hash.h \
        include/isl/list.h \
+       include/isl/local_space.h \
        include/isl/lp.h \
        include/isl/mat.h \
        include/isl/map.h \
@@ -185,6 +204,7 @@ pkginclude_HEADERS = \
        include/isl/point.h \
        include/isl/polynomial.h \
        include/isl/printer.h \
+       include/isl/schedule.h \
        include/isl/seq.h \
        include/isl/set.h \
        include/isl/stream.h \
@@ -219,7 +239,7 @@ pkgconfigdir=$(pkgconfig_libdir)
 pkgconfig_DATA = $(pkgconfig_libfile)
 
 gitversion.h: @GIT_HEAD@
-       echo '#define GIT_HEAD_ID "'@GIT_HEAD_VERSION@'"' > $@
+       $(AM_V_GEN)echo '#define GIT_HEAD_ID "'@GIT_HEAD_VERSION@'"' > $@
 
 install-data-local: $(srcdir)/isl.py
        @libisl=`sed -ne "/^library_names=/{s/.*='//;s/'$$//;s/ .*//;p}" \
index dd90a15..2e4034f 100644 (file)
@@ -337,7 +337,7 @@ struct isl_mat *isl_basic_set_reduced_basis(struct isl_basic_set *bset)
        else {
                isl_mat *eq;
                unsigned nvar = isl_basic_set_total_dim(bset);
-               eq = isl_mat_sub_alloc(bset->ctx, bset->eq, 0, bset->n_eq,
+               eq = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq,
                                        1, nvar);
                eq = isl_mat_left_hermite(eq, 0, NULL, &tab->basis);
                tab->basis = isl_mat_lin_to_aff(tab->basis);
index d8ed9ce..d648968 100644 (file)
@@ -2,6 +2,7 @@ AC_INIT
 AC_CONFIG_AUX_DIR([.])
 AC_CONFIG_MACRO_DIR([m4])
 AM_INIT_AUTOMAKE(isl, 0.06)
+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
 AC_SUBST(versioninfo)
 versioninfo=6:0:0
 
@@ -81,6 +82,9 @@ if test "$with_piplib" != "no"; then
 fi
 AM_CONDITIONAL(HAVE_PIPLIB, test x$have_piplib = xtrue)
 
+PACKAGE_CFLAGS="$GMP_CPPFLAGS"
+PACKAGE_LDFLAGS="$GMP_LDFLAGS"
+PACKAGE_LIBS="-lisl -lgmp"
 AX_CREATE_PKGCONFIG_INFO
 
 AX_DETECT_GIT_HEAD
index d3d82df..d5ece80 100644 (file)
@@ -1108,6 +1108,113 @@ A_1 & \vec c_1
 \right] \vec x' \,\}$ and therefore $\Delta'_i(\vec s)$ is
 a Hilbert basis of this cone \shortcite[Theorem~16.4]{Schrijver1986}.
 
+Note however that, as pointed out by \shortciteN{DeSmet2010personal},
+if there \emph{are} any mixed constraints, then the above procedure may
+not compute the most accurate affine approximation of
+$k \, \Delta_i(\vec s)$ with $k \ge 1$.
+In particular, we only consider the negative mixed constraints that
+happen to appear in the description of $\Delta_i(\vec s)$, while we
+should instead consider \emph{all} valid such constraints.
+It is also sufficient to consider those constraints because any
+constraint that is valid for $k \, \Delta_i(\vec s)$ is also
+valid for $1 \, \Delta_i(\vec s) = \Delta_i(\vec s)$.
+Take therefore any constraint
+$\spv a x + \spv b s + c \ge 0$ valid for $\Delta_i(\vec s)$.
+This constraint is also valid for $k \, \Delta_i(\vec s)$ iff
+$k \, \spv a x + \spv b s + c \ge 0$.
+If $\spv b s + c$ can attain any positive value, then $\spv a x$
+may be negative for some elements of $\Delta_i(\vec s)$.
+We then have $k \, \spv a x < \spv a x$ for $k > 1$ and so the constraint
+is not valid for $k \, \Delta_i(\vec s)$.
+We therefore need to impose $\spv b s + c \le 0$ for all values
+of $\vec s$ such that $\Delta_i(\vec s)$ is non-empty, i.e.,
+$\vec b$ and $c$ need to be such that $- \spv b s - c \ge 0$ is a valid
+constraint of $\Delta_i(\vec s)$.  That is, $(\vec b, c)$ are the opposites
+of the coefficients of a valid constraint of $\Delta_i(\vec s)$.
+The approximation of $k \, \Delta_i(\vec s)$ can therefore be obtained
+using three applications of Farkas' lemma.  The first obtains the coefficients
+of constraints valid for $\Delta_i(\vec s)$.  The second obtains
+the coefficients of constraints valid for the projection of $\Delta_i(\vec s)$
+onto the parameters.  The opposite of the second set is then computed
+and intersected with the first set.  The result is the set of coefficients
+of constraints valid for $k \, \Delta_i(\vec s)$.  A final application
+of Farkas' lemma is needed to obtain the approximation of
+$k \, \Delta_i(\vec s)$ itself.
+
+\begin{example}
+Consider the relation
+$$
+n \to \{\, (x, y) \to (1 + x, 1 - n + y) \mid n \ge 2 \,\}
+.
+$$
+The difference set of this relation is
+$$
+\Delta = n \to \{\, (1, 1 - n) \mid n \ge 2 \,\}
+.
+$$
+Using our approach, we would only consider the mixed constraint
+$y - 1 + n \ge 0$, leading to the following approximation of the
+transitive closure:
+$$
+n \to \{\, (x, y) \to (o_0, o_1) \mid n \ge 2 \wedge o_1 \le 1 - n + y \wedge o_0 \ge 1 + x \,\}
+.
+$$
+If, instead, we apply Farkas's lemma to $\Delta$, i.e.,
+\begin{verbatim}
+D := [n] -> { [1, 1 - n] : n >= 2 };
+CD := coefficients D;
+CD;
+\end{verbatim}
+we obtain
+\begin{verbatim}
+{ rat: coefficients[[c_cst, c_n] -> [i2, i3]] : i3 <= c_n and
+  i3 <= c_cst + 2c_n + i2 }
+\end{verbatim}
+The pure-parametric constraints valid for $\Delta$,
+\begin{verbatim}
+P := { [a,b] -> [] }(D);
+CP := coefficients P;
+CP;
+\end{verbatim}
+are
+\begin{verbatim}
+{ rat: coefficients[[c_cst, c_n] -> []] : c_n >= 0 and 2c_n >= -c_cst }
+\end{verbatim}
+Negating these coefficients and intersecting with \verb+CD+,
+\begin{verbatim}
+NCP := { rat: coefficients[[a,b] -> []]
+              -> coefficients[[-a,-b] -> []] }(CP);
+CK := wrap((unwrap CD) * (dom (unwrap NCP)));
+CK;
+\end{verbatim}
+we obtain
+\begin{verbatim}
+{ rat: [[c_cst, c_n] -> [i2, i3]] : i3 <= c_n and
+  i3 <= c_cst + 2c_n + i2 and c_n <= 0 and 2c_n <= -c_cst }
+\end{verbatim}
+The approximation for $k\,\Delta$,
+\begin{verbatim}
+K := solutions CK;
+K;
+\end{verbatim}
+is then
+\begin{verbatim}
+[n] -> { rat: [i0, i1] : i1 <= -i0 and i0 >= 1 and i1 <= 2 - n - i0 }
+\end{verbatim}
+Finally, the computed approximation for $R^+$,
+\begin{verbatim}
+T := unwrap({ [dx,dy] -> [[x,y] -> [x+dx,y+dy]] }(K));
+R := [n] -> { [x,y] -> [x+1,y+1-n] : n >= 2 };
+T := T * ((dom R) -> (ran R));
+T;
+\end{verbatim}
+is
+\begin{verbatim}
+[n] -> { [x, y] -> [o0, o1] : o1 <= x + y - o0 and
+         o0 >= 1 + x and o1 <= 2 - n + x + y - o0 and n >= 2 }
+\end{verbatim}
+\end{example}
+
 Existentially quantified variables can be handled by
 classifying them into variables that are uniquely
 determined by the parameters, variables that are independent
index 9715833..cfe8081 100644 (file)
@@ -304,3 +304,10 @@ ignore={ },
   month = oct,
   YEAR = {2006}
 }
+
+@misc{DeSmet2010personal,
+    author = "De Smet, Sven",
+    title = "personal communication",
+    year = 2010,
+    month = apr,
+}
index f084a90..91b3db0 100644 (file)
@@ -22,6 +22,7 @@
 \providecommand{\floor}[1]{\left\lfloor#1\right\rfloor}
 \providecommand{\ceil}[1]{\left\lceil#1\right\rceil}
 \def\sp#1#2{\langle #1, #2 \rangle}
+\def\spv#1#2{\langle\vec #1,\vec #2\rangle}
 
 \newtheorem{theorem}{Theorem}
 \newaliascnt{example}{theorem}
index c5d09ff..2e3c026 100644 (file)
@@ -79,6 +79,16 @@ is now expressed as the domain of the resulting relation.
 
 =back
 
+=head3 Changes since isl-0.06
+
+=over
+
+=item * The format of C<isl_printer_print_qpolynomial>'s
+C<ISL_FORMAT_ISL> output has changed.
+Use C<ISL_FORMAT_C> to obtain the old output.
+
+=back
+
 =head1 Installation
 
 The source of C<isl> can be obtained either as a tarball
@@ -456,6 +466,10 @@ specification of the original object.
        __isl_give isl_dim *isl_union_map_get_dim(
                __isl_keep isl_union_map *umap);
 
+       #include <isl/constraint.h>
+       __isl_give isl_dim *isl_constraint_get_dim(
+               __isl_keep isl_constraint *constraint);
+
        #include <isl/polynomial.h>
        __isl_give isl_dim *isl_qpolynomial_get_dim(
                __isl_keep isl_qpolynomial *qp);
@@ -466,6 +480,10 @@ specification of the original object.
        __isl_give isl_dim *isl_union_pw_qpolynomial_fold_get_dim(
                __isl_keep isl_union_pw_qpolynomial_fold *upwf);
 
+       #include <isl/aff.h>
+       __isl_give isl_dim *isl_aff_get_dim(
+               __isl_keep isl_aff *aff);
+
 The names of the individual dimensions may be set or read off
 using the following functions.
 
@@ -545,6 +563,45 @@ specifications using the following functions.
 Note that if dimensions are added or removed from a space, then
 the name and the internal structure are lost.
 
+=head2 Local Spaces
+
+A local space is essentially a dimension specification with
+zero or more existentially quantified variables.
+The local space of a basic set or relation can be obtained
+using the following functions.
+
+       #include <isl/set.h>
+       __isl_give isl_local_space *isl_basic_set_get_local_space(
+               __isl_keep isl_basic_set *bset);
+
+       #include <isl/map.h>
+       __isl_give isl_local_space *isl_basic_map_get_local_space(
+               __isl_keep isl_basic_map *bmap);
+
+A new local space can be created from a dimension specification using
+
+       #include <isl/local_space.h>
+       __isl_give isl_local_space *isl_local_space_from_dim(
+               __isl_take isl_dim *dim);
+
+They can be inspected, copied and freed using the following functions.
+
+       #include <isl/local_space.h>
+       isl_ctx *isl_local_space_get_ctx(
+               __isl_keep isl_local_space *ls);
+       int isl_local_space_dim(__isl_keep isl_local_space *ls,
+               enum isl_dim_type type);
+       const char *isl_local_space_get_dim_name(
+               __isl_keep isl_local_space *ls,
+               enum isl_dim_type type, unsigned pos);
+       __isl_give isl_dim *isl_local_space_get_dim(
+               __isl_keep isl_local_space *ls);
+       __isl_give isl_div *isl_local_space_get_div(
+               __isl_keep isl_local_space *ls, int pos);
+       __isl_give isl_local_space *isl_local_space_copy(
+               __isl_keep isl_local_space *ls);
+       void *isl_local_space_free(__isl_take isl_local_space *ls);
+
 =head2 Input and Output
 
 C<isl> supports its own input/output format, which is similar
@@ -748,6 +805,10 @@ is only used to specify the parameters.
                __isl_take isl_dim *dim);
        __isl_give isl_map *isl_map_universe(
                __isl_take isl_dim *dim);
+       __isl_give isl_union_set *isl_union_set_universe(
+               __isl_take isl_union_set *uset);
+       __isl_give isl_union_map *isl_union_map_universe(
+               __isl_take isl_union_map *umap);
 
 The sets and relations constructed by the functions above
 contain all integer values, while those constructed by the
@@ -847,7 +908,7 @@ from a universe set or relation, adding equality and/or
 inequality constraints and then projecting out the
 existentially quantified variables, if any.
 Constraints can be constructed, manipulated and
-added to basic sets and relations using the following functions.
+added to (basic) sets and relations using the following functions.
 
        #include <isl/constraint.h>
        __isl_give isl_constraint *isl_equality_alloc(
@@ -865,6 +926,12 @@ added to basic sets and relations using the following functions.
        __isl_give isl_basic_set *isl_basic_set_add_constraint(
                __isl_take isl_basic_set *bset,
                __isl_take isl_constraint *constraint);
+       __isl_give isl_map *isl_map_add_constraint(
+               __isl_take isl_map *map,
+               __isl_take isl_constraint *constraint);
+       __isl_give isl_set *isl_set_add_constraint(
+               __isl_take isl_set *set,
+               __isl_take isl_constraint *constraint);
 
 For example, to create a set containing the even integers
 between 10 and 42, you would use the following code.
@@ -975,6 +1042,8 @@ using the following functions, which compute an overapproximation.
                __isl_take isl_basic_map *bmap);
        __isl_give isl_set *isl_set_remove_divs(
                __isl_take isl_set *set);
+       __isl_give isl_map *isl_map_remove_divs(
+               __isl_take isl_map *map);
 
 To iterate over all the sets or maps in a union set or map, use
 
@@ -1057,6 +1126,9 @@ the following functions.
        void isl_constraint_get_coefficient(
                __isl_keep isl_constraint *constraint,
                enum isl_dim_type type, int pos, isl_int *v);
+       int isl_constraint_involves_dims(
+               __isl_keep isl_constraint *constraint,
+               enum isl_dim_type type, unsigned first, unsigned n);
 
 The explicit representations of the existentially quantified
 variables can be inspected using the following functions.
@@ -1066,6 +1138,7 @@ to C<isl_set_compute_divs> or C<isl_map_compute_divs>.
 
        __isl_give isl_div *isl_constraint_div(
                __isl_keep isl_constraint *constraint, int pos);
+       isl_ctx *isl_div_get_ctx(__isl_keep isl_div *div);
        void isl_div_get_constant(__isl_keep isl_div *div,
                isl_int *v);
        void isl_div_get_denominator(__isl_keep isl_div *div,
@@ -1147,17 +1220,18 @@ of the parameters.
 =item * Emptiness
 
 The following functions test whether the given set or relation
-contains any integer points.  The ``fast'' variants do not perform
+contains any integer points.  The ``plain'' variants do not perform
 any computations, but simply check if the given set or relation
 is already known to be empty.
 
-       int isl_basic_set_fast_is_empty(__isl_keep isl_basic_set *bset);
+       int isl_basic_set_plain_is_empty(__isl_keep isl_basic_set *bset);
        int isl_basic_set_is_empty(__isl_keep isl_basic_set *bset);
+       int isl_set_plain_is_empty(__isl_keep isl_set *set);
        int isl_set_is_empty(__isl_keep isl_set *set);
        int isl_union_set_is_empty(__isl_keep isl_union_set *uset);
-       int isl_basic_map_fast_is_empty(__isl_keep isl_basic_map *bmap);
+       int isl_basic_map_plain_is_empty(__isl_keep isl_basic_map *bmap);
        int isl_basic_map_is_empty(__isl_keep isl_basic_map *bmap);
-       int isl_map_fast_is_empty(__isl_keep isl_map *map);
+       int isl_map_plain_is_empty(__isl_keep isl_map *map);
        int isl_map_is_empty(__isl_keep isl_map *map);
        int isl_union_map_is_empty(__isl_keep isl_union_map *umap);
 
@@ -1165,19 +1239,30 @@ is already known to be empty.
 
        int isl_basic_set_is_universe(__isl_keep isl_basic_set *bset);
        int isl_basic_map_is_universe(__isl_keep isl_basic_map *bmap);
-       int isl_set_fast_is_universe(__isl_keep isl_set *set);
+       int isl_set_plain_is_universe(__isl_keep isl_set *set);
 
 =item * Single-valuedness
 
        int isl_map_is_single_valued(__isl_keep isl_map *map);
+       int isl_union_map_is_single_valued(__isl_keep isl_union_map *umap);
+
+=item * Injectivity
+
+       int isl_map_plain_is_injective(__isl_keep isl_map *map);
+       int isl_map_is_injective(__isl_keep isl_map *map);
+       int isl_union_map_plain_is_injective(
+               __isl_keep isl_union_map *umap);
+       int isl_union_map_is_injective(
+               __isl_keep isl_union_map *umap);
 
 =item * Bijectivity
 
        int isl_map_is_bijective(__isl_keep isl_map *map);
+       int isl_union_map_is_bijective(__isl_keep isl_union_map *umap);
 
 =item * Wrapping
 
-The followning functions check whether the domain of the given
+The following functions check whether the domain of the given
 (basic) set is a wrapped relation.
 
        int isl_basic_set_is_wrapping(
@@ -1202,7 +1287,7 @@ i.e., whether both domain and range are nested relations.
 
 =item * Equality
 
-       int isl_set_fast_is_equal(__isl_keep isl_set *set1,
+       int isl_set_plain_is_equal(__isl_keep isl_set *set1,
                __isl_keep isl_set *set2);
        int isl_set_is_equal(__isl_keep isl_set *set1,
                __isl_keep isl_set *set2);
@@ -1214,7 +1299,7 @@ i.e., whether both domain and range are nested relations.
                __isl_keep isl_basic_map *bmap2);
        int isl_map_is_equal(__isl_keep isl_map *map1,
                __isl_keep isl_map *map2);
-       int isl_map_fast_is_equal(__isl_keep isl_map *map1,
+       int isl_map_plain_is_equal(__isl_keep isl_map *map1,
                __isl_keep isl_map *map2);
        int isl_union_map_is_equal(
                __isl_keep isl_union_map *umap1,
@@ -1222,7 +1307,7 @@ i.e., whether both domain and range are nested relations.
 
 =item * Disjointness
 
-       int isl_set_fast_is_disjoint(__isl_keep isl_set *set1,
+       int isl_set_plain_is_disjoint(__isl_keep isl_set *set1,
                __isl_keep isl_set *set2);
 
 =item * Subset
@@ -1316,6 +1401,15 @@ i.e., whether both domain and range are nested relations.
 The functions above construct a (basic, regular or union) relation
 that maps (a wrapped version of) the input relation to its domain or range.
 
+=item * Elimination
+
+       __isl_give isl_set *isl_set_eliminate(
+               __isl_take isl_set *set, enum isl_dim_type type,
+               unsigned first, unsigned n);
+
+Eliminate the coefficients for the given dimensions from the constraints,
+without removing the dimensions.
+
 =item * Identity
 
        __isl_give isl_map *isl_set_identity(
@@ -1377,6 +1471,13 @@ basic set or relation.
 Simplify the representation of a set or relation by detecting implicit
 equalities.
 
+=item * Removing redundant constraints
+
+       __isl_give isl_basic_set *isl_basic_set_remove_redundancies(
+               __isl_take isl_basic_set *bset);
+       __isl_give isl_basic_map *isl_basic_map_remove_redundancies(
+               __isl_take isl_basic_map *bmap);
+
 =item * Convex hull
 
        __isl_give isl_basic_set *isl_set_convex_hull(
@@ -1442,6 +1543,43 @@ that contains the whole input set or relation.
 In case of union sets and relations, the polyhedral hull is computed
 per space.
 
+=item * Optimization
+
+       #include <isl/ilp.h>
+       enum isl_lp_result isl_set_max(__isl_keep isl_set *set,
+               __isl_keep isl_aff *obj, isl_int *opt);
+
+Compute the maximum of the integer affine expression C<obj>
+over the points in C<set>, returning the result in C<opt>.
+The return value may be one of C<isl_lp_error>,
+C<isl_lp_ok>, C<isl_lp_unbounded> or C<isl_lp_empty>.
+
+=item * Dual
+
+The following functions compute either the set of (rational) coefficient
+values of valid constraints for the given set or the set of (rational)
+values satisfying the constraints with coefficients from the given set.
+Internally, these two sets of functions perform essentially the
+same operations, except that the set of coefficients is assumed to
+be a cone, while the set of values may be any polyhedron.
+The current implementation is based on the Farkas lemma and
+Fourier-Motzkin elimination, but this may change or be made optional
+in future.  In particular, future implementations may use different
+dualization algorithms or skip the elimination step.
+
+       __isl_give isl_basic_set *isl_basic_set_coefficients(
+               __isl_take isl_basic_set *bset);
+       __isl_give isl_basic_set *isl_set_coefficients(
+               __isl_take isl_set *set);
+       __isl_give isl_union_set *isl_union_set_coefficients(
+               __isl_take isl_union_set *bset);
+       __isl_give isl_basic_set *isl_basic_set_solutions(
+               __isl_take isl_basic_set *bset);
+       __isl_give isl_basic_set *isl_set_solutions(
+               __isl_take isl_set *set);
+       __isl_give isl_union_set *isl_union_set_solutions(
+               __isl_take isl_union_set *bset);
+
 =item * Power
 
        __isl_give isl_map *isl_map_power(__isl_take isl_map *map,
@@ -1521,6 +1659,21 @@ then the name of the space is also removed.
 The function above constructs a relation
 that maps the input set to a flattened version of the set.
 
+=item * Lifting
+
+Lift the input set to a space with extra dimensions corresponding
+to the existentially quantified variables in the input.
+In particular, the result lives in a wrapped map where the domain
+is the original space and the range corresponds to the original
+existentially quantified variables.
+
+       __isl_give isl_basic_set *isl_basic_set_lift(
+               __isl_take isl_basic_set *bset);
+       __isl_give isl_set *isl_set_lift(
+               __isl_take isl_set *set);
+       __isl_give isl_union_set *isl_union_set_lift(
+               __isl_take isl_union_set *uset);
+
 =item * Internal Product
 
        __isl_give isl_basic_map *isl_basic_map_zip(
@@ -1533,6 +1686,20 @@ that maps the input set to a flattened version of the set.
 Given a relation with nested relations for domain and range,
 interchange the range of the domain with the domain of the range.
 
+=item * Aligning parameters
+
+       __isl_give isl_set *isl_set_align_params(
+               __isl_take isl_set *set,
+               __isl_take isl_dim *model);
+       __isl_give isl_map *isl_map_align_params(
+               __isl_take isl_map *map,
+               __isl_take isl_dim *model);
+
+Change the order of the parameters of the given set or relation
+such that the first parameters match those of C<model>.
+This may involve the introduction of extra parameters.
+All parameters need to be named.
+
 =item * Dimension manipulation
 
        __isl_give isl_set *isl_set_add_dims(
@@ -1545,7 +1712,9 @@ interchange the range of the domain with the domain of the range.
 It is usually not advisable to directly change the (input or output)
 space of a set or a relation as this removes the name and the internal
 structure of the space.  However, the above functions can be useful
-to add new parameters.
+to add new parameters, assuming
+C<isl_set_align_params> and C<isl_map_align_params>
+are not sufficient.
 
 =back
 
@@ -1842,12 +2011,15 @@ Matrices can be created, copied and freed using the following functions.
 Note that the elements of a newly created matrix may have arbitrary values.
 The elements can be changed and inspected using the following functions.
 
+       isl_ctx *isl_mat_get_ctx(__isl_keep isl_mat *mat);
        int isl_mat_rows(__isl_keep isl_mat *mat);
        int isl_mat_cols(__isl_keep isl_mat *mat);
        int isl_mat_get_element(__isl_keep isl_mat *mat,
                int row, int col, isl_int *v);
        __isl_give isl_mat *isl_mat_set_element(__isl_take isl_mat *mat,
                int row, int col, isl_int v);
+       __isl_give isl_mat *isl_mat_set_element_si(__isl_take isl_mat *mat,
+               int row, int col, int v);
 
 C<isl_mat_get_element> will return a negative value if anything went wrong.
 In that case, the value of C<*v> is undefined.
@@ -1865,6 +2037,92 @@ 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);
+
+A (rational) bound on a dimension can be extracted from an C<isl_constraint>
+using the following function.  The constraint is required to have
+a non-zero coefficient for the specified dimension.
+
+       #include <isl/constraint.h>
+       __isl_give isl_aff *isl_constraint_get_bound(
+               __isl_keep isl_constraint *constraint,
+               enum isl_dim_type type, int pos);
+
+Conversely, an equality constraint can be constructed, equating
+the affine expression to zero, using
+
+       __isl_give isl_constraint *isl_equality_from_aff(
+               __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
@@ -2030,6 +2288,8 @@ on the resulting quasipolynomials
        __isl_give isl_qpolynomial *isl_qpolynomial_var(
                __isl_take isl_dim *dim,
                enum isl_dim_type type, unsigned pos);
+       __isl_give isl_qpolynomial *isl_qpolynomial_from_aff(
+               __isl_take isl_aff *aff);
 
 The zero piecewise quasipolynomial or a piecewise quasipolynomial
 with a single cell can be created using the following functions.
@@ -2215,9 +2475,17 @@ are returned in C<*n> and C<*d>, respectively.
                __isl_take isl_union_pw_qpolynomial *upwpq,
                __isl_take isl_union_set *uset);
 
+       __isl_give isl_qpolynomial *isl_qpolynomial_align_params(
+               __isl_take isl_qpolynomial *qp,
+               __isl_take isl_dim *model);
+
        __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_coalesce(
                __isl_take isl_union_pw_qpolynomial *upwqp);
 
+       __isl_give isl_qpolynomial *isl_qpolynomial_gist(
+               __isl_take isl_qpolynomial *qp,
+               __isl_take isl_set *context);
+
        __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_gist(
                __isl_take isl_pw_qpolynomial *pwqp,
                __isl_take isl_set *context);
@@ -2554,6 +2822,51 @@ Any of C<must_dep>, C<may_dep>, C<must_no_source>
 or C<may_no_source> may be C<NULL>, but a C<NULL> value for
 any of the other arguments is treated as an error.
 
+=head2 Scheduling
+
+B<The functionality described in this section is fairly new
+and may be subject to change.>
+
+The following function can be used to compute a schedule
+for a union of domains.  The generated schedule respects
+all C<validity> dependences.  That is, all dependence distances
+over these dependences in the scheduled space are lexicographically
+positive.  The generated schedule schedule also tries to minimize
+the dependence distances over C<proximity> dependences.
+Moreover, it tries to obtain sequences (bands) of schedule dimensions
+for groups of domains where the dependence distances have only
+non-negative values.
+The algorithm used to construct the schedule is similar to that
+of C<Pluto>.
+
+       #include <isl/schedule.h>
+       __isl_give isl_schedule *isl_union_set_compute_schedule(
+               __isl_take isl_union_set *domain,
+               __isl_take isl_union_map *validity,
+               __isl_take isl_union_map *proximity);
+       void *isl_schedule_free(__isl_take isl_schedule *sched);
+
+A mapping from the domains to the scheduled space can be obtained
+from an C<isl_schedule> using the following function.
+
+       __isl_give isl_union_map *isl_schedule_get_map(
+               __isl_keep isl_schedule *sched);
+
+This mapping can also be obtained in pieces using the following functions.
+
+       int isl_schedule_n_band(__isl_keep isl_schedule *sched);
+       __isl_give isl_union_map *isl_schedule_get_band(
+               __isl_keep isl_schedule *sched, unsigned band);
+
+C<isl_schedule_n_band> returns the maximal number of bands.
+C<isl_schedule_get_band> returns a union of mappings from a domain to
+the band of consecutive schedule dimensions with the given sequence
+number for that domain.  Bands with the same sequence number but for
+different domains may be completely unrelated.
+Within a band, the corresponding coordinates of the distance vectors
+are all non-negative, assuming that the coordinates for all previous
+bands are all zero.
+
 =head2 Parametric Vertex Enumeration
 
 The parametric vertex enumeration described in this section
@@ -2656,27 +2969,3 @@ is given, then the constant should appear in the last column.
 
 Given a polytope, C<isl_polytope_scan> prints
 all integer points in the polytope.
-
-=head1 C<isl-polylib>
-
-The C<isl-polylib> library provides the following functions for converting
-between C<isl> objects and C<PolyLib> objects.
-The library is distributed separately for licensing reasons.
-
-       #include <isl_set_polylib.h>
-       __isl_give isl_basic_set *isl_basic_set_new_from_polylib(
-               Polyhedron *P, __isl_take isl_dim *dim);
-       Polyhedron *isl_basic_set_to_polylib(
-               __isl_keep isl_basic_set *bset);
-       __isl_give isl_set *isl_set_new_from_polylib(Polyhedron *D,
-               __isl_take isl_dim *dim);
-       Polyhedron *isl_set_to_polylib(__isl_keep isl_set *set);
-
-       #include <isl_map_polylib.h>
-       __isl_give isl_basic_map *isl_basic_map_new_from_polylib(
-               Polyhedron *P, __isl_take isl_dim *dim);
-       __isl_give isl_map *isl_map_new_from_polylib(Polyhedron *D,
-               __isl_take isl_dim *dim);
-       Polyhedron *isl_basic_map_to_polylib(
-               __isl_keep isl_basic_map *bmap);
-       Polyhedron *isl_map_to_polylib(__isl_keep isl_map *map);
diff --git a/include/isl/aff.h b/include/isl/aff.h
new file mode 100644 (file)
index 0000000..1769857
--- /dev/null
@@ -0,0 +1,57 @@
+#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_dim *isl_aff_get_dim(__isl_keep isl_aff *aff);
+__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
index 970709a..5b591da 100644 (file)
 #ifndef ISL_CONSTRAINT_H
 #define ISL_CONSTRAINT_H
 
+#include <isl/aff.h>
 #include <isl/div.h>
 #include <isl/set.h>
+#include <isl/printer.h>
 
 #if defined(__cplusplus)
 extern "C" {
@@ -26,6 +28,8 @@ struct isl_constraint {
 };
 typedef struct isl_constraint isl_constraint;
 
+isl_ctx *isl_constraint_get_ctx(__isl_keep isl_constraint *c);
+
 __isl_give isl_constraint *isl_equality_alloc(__isl_take isl_dim *dim);
 __isl_give isl_constraint *isl_inequality_alloc(__isl_take isl_dim *dim);
 struct isl_constraint *isl_basic_set_constraint(struct isl_basic_set *bset,
@@ -57,6 +61,10 @@ __isl_give isl_basic_map *isl_basic_map_add_constraint(
        __isl_take isl_basic_map *bmap, __isl_take isl_constraint *constraint);
 __isl_give isl_basic_set *isl_basic_set_add_constraint(
        __isl_take isl_basic_set *bset, __isl_take isl_constraint *constraint);
+__isl_give isl_map *isl_map_add_constraint(__isl_take isl_map *map,
+       __isl_take isl_constraint *constraint);
+__isl_give isl_set *isl_set_add_constraint(__isl_take isl_set *set,
+       __isl_take isl_constraint *constraint);
 
 int isl_basic_map_has_defining_equality(
        __isl_keep isl_basic_map *bmap, enum isl_dim_type type, int pos,
@@ -69,9 +77,14 @@ int isl_basic_set_has_defining_inequalities(
        struct isl_constraint **lower,
        struct isl_constraint **upper);
 
+__isl_give isl_dim *isl_constraint_get_dim(
+       __isl_keep isl_constraint *constraint);
 int isl_constraint_dim(struct isl_constraint *constraint,
        enum isl_dim_type type);
 
+int isl_constraint_involves_dims(__isl_keep isl_constraint *constraint,
+       enum isl_dim_type type, unsigned first, unsigned n);
+
 const char *isl_constraint_get_dim_name(__isl_keep isl_constraint *constraint,
        enum isl_dim_type type, unsigned pos);
 void isl_constraint_get_constant(__isl_keep isl_constraint *constraint,
@@ -102,6 +115,14 @@ __isl_give isl_basic_map *isl_basic_map_from_constraint(
 struct isl_basic_set *isl_basic_set_from_constraint(
        struct isl_constraint *constraint);
 
+__isl_give isl_aff *isl_constraint_get_bound(
+       __isl_keep isl_constraint *constraint, enum isl_dim_type type, int pos);
+__isl_give isl_constraint *isl_equality_from_aff(__isl_take isl_aff *aff);
+
+__isl_give isl_printer *isl_printer_print_constraint(__isl_take isl_printer *p,
+       __isl_keep isl_constraint *c);
+void isl_constraint_dump(__isl_keep isl_constraint *c);
+
 #if defined(__cplusplus)
 }
 #endif
index d7df544..86ac0ca 100644 (file)
 #define ISL_DIV_H
 
 #include <isl/dim.h>
-#include <isl/set.h>
 
 #if defined(__cplusplus)
 extern "C" {
 #endif
 
-struct isl_div {
-       int ref;
-       struct isl_ctx *ctx;
-
-       struct isl_basic_map    *bmap;
-       isl_int                 **line;
-};
+struct isl_div;
 typedef struct isl_div isl_div;
 
+isl_ctx *isl_div_get_ctx(__isl_keep isl_div *div);
+
 struct isl_div *isl_div_alloc(struct isl_dim *dim);
-struct isl_div *isl_basic_map_div(struct isl_basic_map *bmap, int pos);
-struct isl_div *isl_basic_set_div(struct isl_basic_set *bset, int pos);
 __isl_give isl_div *isl_div_copy(__isl_keep isl_div *div);
 void isl_div_free(struct isl_div *c);
 
index f7db311..9d19543 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef ISL_ILP_H
 #define ISL_ILP_H
 
+#include <isl/aff.h>
 #include <isl/lp.h>
 
 #if defined(__cplusplus)
@@ -19,6 +20,8 @@ extern "C" {
 enum isl_lp_result isl_basic_set_solve_ilp(struct isl_basic_set *bset, int max,
                                      isl_int *f, isl_int *opt,
                                      struct isl_vec **sol_p);
+enum isl_lp_result isl_set_max(__isl_keep isl_set *set,
+       __isl_keep isl_aff *obj, isl_int *opt);
 
 #if defined(__cplusplus)
 }
diff --git a/include/isl/local_space.h b/include/isl/local_space.h
new file mode 100644 (file)
index 0000000..24c02b5
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef ISL_LOCAL_SPACE_H
+#define ISL_LOCAL_SPACE_H
+
+#include <isl/div.h>
+#include <isl/printer.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_local_space;
+typedef struct isl_local_space isl_local_space;
+
+isl_ctx *isl_local_space_get_ctx(__isl_keep isl_local_space *ls);
+
+__isl_give isl_local_space *isl_local_space_from_dim(__isl_take isl_dim *dim);
+
+__isl_give isl_local_space *isl_local_space_copy(
+       __isl_keep isl_local_space *ls);
+void *isl_local_space_free(__isl_take isl_local_space *ls);
+
+int isl_local_space_dim(__isl_keep isl_local_space *ls,
+       enum isl_dim_type type);
+const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls,
+       enum isl_dim_type type, unsigned pos);
+__isl_give isl_dim *isl_local_space_get_dim(__isl_keep isl_local_space *ls);
+__isl_give isl_div *isl_local_space_get_div(__isl_keep isl_local_space *ls,
+       int pos);
+
+__isl_give isl_printer *isl_printer_print_local_space(__isl_take isl_printer *p,
+       __isl_keep isl_local_space *ls);
+void isl_local_space_dump(__isl_keep isl_local_space *ls);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
index 7e4ef78..530152a 100644 (file)
 #include <isl/ctx.h>
 #include <isl/blk.h>
 #include <isl/dim.h>
+#include <isl/div.h>
 #include <isl/vec.h>
 #include <isl/mat.h>
 #include <isl/printer.h>
+#include <isl/local_space.h>
 
 #if defined(__cplusplus)
 extern "C" {
@@ -69,6 +71,11 @@ isl_ctx *isl_map_get_ctx(__isl_keep isl_map *map);
 __isl_give isl_dim *isl_basic_map_get_dim(__isl_keep isl_basic_map *bmap);
 __isl_give isl_dim *isl_map_get_dim(__isl_keep isl_map *map);
 
+struct isl_div *isl_basic_map_div(struct isl_basic_map *bmap, int pos);
+
+__isl_give isl_local_space *isl_basic_map_get_local_space(
+       __isl_keep isl_basic_map *bmap);
+
 __isl_give isl_basic_map *isl_basic_map_set_tuple_name(
        __isl_take isl_basic_map *bmap, enum isl_dim_type type, const char *s);
 const char *isl_basic_map_get_tuple_name(__isl_keep isl_basic_map *bmap,
@@ -220,11 +227,12 @@ struct isl_basic_map *isl_map_copy_basic_map(struct isl_map *map);
 __isl_give isl_map *isl_map_drop_basic_map(__isl_take isl_map *map,
                                                __isl_keep isl_basic_map *bmap);
 
-int isl_basic_map_fast_is_fixed(struct isl_basic_map *bmap,
+int isl_basic_map_plain_is_fixed(struct isl_basic_map *bmap,
        enum isl_dim_type type, unsigned pos, isl_int *val);
 
 int isl_basic_map_image_is_bounded(__isl_keep isl_basic_map *bmap);
 int isl_basic_map_is_universe(__isl_keep isl_basic_map *bmap);
+int isl_basic_map_plain_is_empty(__isl_keep isl_basic_map *bmap);
 int isl_basic_map_fast_is_empty(__isl_keep isl_basic_map *bmap);
 int isl_basic_map_is_empty(__isl_keep isl_basic_map *bmap);
 int isl_basic_map_is_subset(__isl_keep isl_basic_map *bmap1,
@@ -327,6 +335,7 @@ __isl_give isl_map *isl_map_project_out(__isl_take isl_map *map,
                enum isl_dim_type type, unsigned first, unsigned n);
 __isl_give isl_basic_map *isl_basic_map_remove_divs(
        __isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_remove_divs(__isl_take isl_map *map);
 __isl_give isl_map *isl_map_remove_dims(__isl_take isl_map *map,
        enum isl_dim_type type, unsigned first, unsigned n);
 struct isl_map *isl_map_remove_inputs(struct isl_map *map,
@@ -364,13 +373,16 @@ struct isl_map *isl_map_from_set(struct isl_set *set, struct isl_dim *dim);
 struct isl_set *isl_set_from_map(struct isl_map *map);
 __isl_give isl_basic_map *isl_map_sample(__isl_take isl_map *map);
 
+int isl_map_plain_is_empty(__isl_keep isl_map *map);
 int isl_map_fast_is_empty(__isl_keep isl_map *map);
-int isl_map_fast_is_universe(__isl_keep isl_map *map);
+int isl_map_plain_is_universe(__isl_keep isl_map *map);
 int isl_map_is_empty(__isl_keep isl_map *map);
 int isl_map_is_subset(__isl_keep isl_map *map1, __isl_keep isl_map *map2);
 int isl_map_is_strict_subset(__isl_keep isl_map *map1, __isl_keep isl_map *map2);
 int isl_map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2);
 int isl_map_is_single_valued(__isl_keep isl_map *map);
+int isl_map_plain_is_injective(__isl_keep isl_map *map);
+int isl_map_is_injective(__isl_keep isl_map *map);
 int isl_map_is_bijective(__isl_keep isl_map *map);
 int isl_map_is_translation(__isl_keep isl_map *map);
 int isl_map_has_equal_dim(__isl_keep isl_map *map1, __isl_keep isl_map *map2);
@@ -387,9 +399,13 @@ __isl_give isl_map *isl_map_align_divs(__isl_take isl_map *map);
 
 void isl_map_print_internal(__isl_keep isl_map *map, FILE *out, int indent);
 
-int isl_map_fast_input_is_fixed(struct isl_map *map,
+int isl_map_plain_input_is_fixed(__isl_keep isl_map *map,
                unsigned in, isl_int *val);
-int isl_map_fast_is_fixed(struct isl_map *map,
+int isl_map_fast_is_fixed(__isl_keep isl_map *map,
+       enum isl_dim_type type, unsigned pos, isl_int *val);
+int isl_map_plain_is_fixed(struct isl_map *map,
+       enum isl_dim_type type, unsigned pos, isl_int *val);
+int isl_map_fast_is_fixed(__isl_keep isl_map *map,
        enum isl_dim_type type, unsigned pos, isl_int *val);
 
 __isl_give isl_basic_map *isl_basic_map_gist(__isl_take isl_basic_map *bmap,
@@ -401,6 +417,7 @@ __isl_give isl_map *isl_map_gist_basic_map(__isl_take isl_map *map,
 
 __isl_give isl_map *isl_map_coalesce(__isl_take isl_map *map);
 
+int isl_map_plain_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2);
 int isl_map_fast_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2);
 
 uint32_t isl_map_get_hash(__isl_keep isl_map *map);
@@ -425,6 +442,9 @@ __isl_give isl_map *isl_map_lex_ge_map(__isl_take isl_map *map1,
 __isl_give isl_map *isl_map_lex_gt_map(__isl_take isl_map *map1,
        __isl_take isl_map *map2);
 
+__isl_give isl_map *isl_map_align_params(__isl_take isl_map *map,
+       __isl_take isl_dim *model);
+
 __isl_give isl_mat *isl_basic_map_equalities_matrix(
                __isl_keep isl_basic_map *bmap, enum isl_dim_type c1,
                enum isl_dim_type c2, enum isl_dim_type c3,
index 8345236..dfa74c2 100644 (file)
@@ -24,6 +24,8 @@ extern "C" {
 struct isl_mat;
 typedef struct isl_mat isl_mat;
 
+isl_ctx *isl_mat_get_ctx(__isl_keep isl_mat *mat);
+
 __isl_give isl_mat *isl_mat_alloc(struct isl_ctx *ctx,
        unsigned n_row, unsigned n_col);
 struct isl_mat *isl_mat_dup(struct isl_mat *mat);
@@ -39,13 +41,8 @@ int isl_mat_cols(__isl_keep isl_mat *mat);
 int isl_mat_get_element(__isl_keep isl_mat *mat, int row, int col, isl_int *v);
 __isl_give isl_mat *isl_mat_set_element(__isl_take isl_mat *mat,
        int row, int col, isl_int v);
-
-struct isl_mat *isl_mat_sub_alloc(struct isl_ctx *ctx, isl_int **row,
-       unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col);
-void isl_mat_sub_copy(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
-       unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col);
-void isl_mat_sub_neg(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
-       unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col);
+__isl_give isl_mat *isl_mat_set_element_si(__isl_take isl_mat *mat,
+       int row, int col, int v);
 
 struct isl_mat *isl_mat_swap_cols(struct isl_mat *mat, unsigned i, unsigned j);
 struct isl_mat *isl_mat_swap_rows(struct isl_mat *mat, unsigned i, unsigned j);
@@ -84,6 +81,9 @@ __isl_give isl_mat *isl_mat_add_rows(__isl_take isl_mat *mat, unsigned n);
 __isl_give isl_mat *isl_mat_insert_zero_cols(__isl_take isl_mat *mat,
        unsigned first, unsigned n);
 __isl_give isl_mat *isl_mat_add_zero_cols(__isl_take isl_mat *mat, unsigned n);
+__isl_give isl_mat *isl_mat_insert_zero_rows(__isl_take isl_mat *mat,
+       unsigned row, unsigned n);
+__isl_give isl_mat *isl_mat_add_zero_rows(__isl_take isl_mat *mat, unsigned n);
 
 void isl_mat_col_add(__isl_keep isl_mat *mat, int dst_col, int src_col);
 void isl_mat_col_mul(struct isl_mat *mat, int dst_col, isl_int f, int src_col);
@@ -100,7 +100,10 @@ __isl_give isl_mat *isl_mat_vec_concat(__isl_take isl_mat *top,
 
 int isl_mat_is_equal(__isl_keep isl_mat *mat1, __isl_keep isl_mat *mat2);
 
-void isl_mat_dump(struct isl_mat *mat, FILE *out, int indent);
+int isl_mat_initial_non_zero_cols(__isl_keep isl_mat *mat);
+
+void isl_mat_print_internal(__isl_keep isl_mat *mat, FILE *out, int indent);
+void isl_mat_dump(__isl_keep isl_mat *mat);
 
 #if defined(__cplusplus)
 }
index 30628a1..a60d2c8 100644 (file)
@@ -58,6 +58,8 @@ struct isl_options {
        #define                 ISL_CONVEX_HULL_WRAP    0
        #define                 ISL_CONVEX_HULL_FM      1
        int                     convex;
+
+       int                     schedule_parametric;
 };
 
 ISL_ARG_DECL(isl_options, struct isl_options, isl_options_arg)
index 7ad34c1..d24469c 100644 (file)
@@ -9,6 +9,7 @@
 #include <isl/point.h>
 #include <isl/printer.h>
 #include <isl/union_set.h>
+#include <isl/aff.h>
 
 #if defined(__cplusplus)
 extern "C" {
@@ -94,6 +95,9 @@ int isl_qpolynomial_as_polynomial_on_domain(__isl_keep isl_qpolynomial *qp,
 __isl_give isl_qpolynomial *isl_qpolynomial_homogenize(
        __isl_take isl_qpolynomial *poly);
 
+__isl_give isl_qpolynomial *isl_qpolynomial_align_params(
+       __isl_take isl_qpolynomial *qp, __isl_take isl_dim *model);
+
 struct isl_term;
 typedef struct isl_term isl_term;
 
@@ -114,9 +118,13 @@ int isl_qpolynomial_foreach_term(__isl_keep isl_qpolynomial *qp,
 __isl_give isl_qpolynomial *isl_qpolynomial_eval(
        __isl_take isl_qpolynomial *qp, __isl_take isl_point *pnt);
 
+__isl_give isl_qpolynomial *isl_qpolynomial_gist(
+       __isl_take isl_qpolynomial *qp, __isl_take isl_set *context);
+
 __isl_give isl_qpolynomial *isl_qpolynomial_from_constraint(
        __isl_take isl_constraint *c, enum isl_dim_type type, unsigned pos);
 __isl_give isl_qpolynomial *isl_qpolynomial_from_term(__isl_take isl_term *term);
+__isl_give isl_qpolynomial *isl_qpolynomial_from_aff(__isl_take isl_aff *aff);
 __isl_give isl_basic_map *isl_basic_map_from_qpolynomial(
        __isl_take isl_qpolynomial *qp);
 
diff --git a/include/isl/schedule.h b/include/isl/schedule.h
new file mode 100644 (file)
index 0000000..07e0965
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef ISL_SCHEDULE_H
+#define ISL_SCHEDULE_H
+
+#include <isl/union_set.h>
+#include <isl/union_map.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_schedule;
+typedef struct isl_schedule isl_schedule;
+
+__isl_give isl_schedule *isl_union_set_compute_schedule(
+       __isl_take isl_union_set *domain,
+       __isl_take isl_union_map *validity,
+       __isl_take isl_union_map *proximity);
+void *isl_schedule_free(__isl_take isl_schedule *sched);
+__isl_give isl_union_map *isl_schedule_get_map(__isl_keep isl_schedule *sched);
+
+int isl_schedule_n_band(__isl_keep isl_schedule *sched);
+__isl_give isl_union_map *isl_schedule_get_band(__isl_keep isl_schedule *sched,
+       unsigned band);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
index 162610d..e50a77c 100644 (file)
@@ -13,6 +13,7 @@
 #include <isl/map.h>
 #include <isl/list.h>
 #include <isl/point.h>
+#include <isl/local_space.h>
 
 #if defined(__cplusplus)
 extern "C" {
@@ -35,6 +36,11 @@ __isl_give isl_dim *isl_set_get_dim(__isl_keep isl_set *set);
 __isl_give isl_set *isl_set_reset_dim(__isl_take isl_set *set,
        __isl_take isl_dim *dim);
 
+struct isl_div *isl_basic_set_div(struct isl_basic_set *bset, int pos);
+
+__isl_give isl_local_space *isl_basic_set_get_local_space(
+       __isl_keep isl_basic_set *bset);
+
 const char *isl_basic_set_get_tuple_name(__isl_keep isl_basic_set *bset);
 const char *isl_set_get_tuple_name(__isl_keep isl_set *set);
 __isl_give isl_set *isl_set_set_tuple_name(__isl_take isl_set *set,
@@ -89,6 +95,8 @@ __isl_give isl_basic_set *isl_basic_set_remove_dims(
 struct isl_basic_set *isl_basic_set_simplify(struct isl_basic_set *bset);
 __isl_give isl_basic_set *isl_basic_set_detect_equalities(
                                                __isl_take isl_basic_set *bset);
+__isl_give isl_basic_set *isl_basic_set_remove_redundancies(
+       __isl_take isl_basic_set *bset);
 __isl_give isl_basic_set *isl_basic_set_list_product(
        __isl_take struct isl_basic_set_list *list);
 
@@ -157,6 +165,7 @@ int isl_basic_set_dims_get_sign(__isl_keep isl_basic_set *bset,
        enum isl_dim_type type, unsigned pos, unsigned n, int *signs);
 
 int isl_basic_set_is_universe(__isl_keep isl_basic_set *bset);
+int isl_basic_set_plain_is_empty(__isl_keep isl_basic_set *bset);
 int isl_basic_set_fast_is_empty(__isl_keep isl_basic_set *bset);
 int isl_basic_set_is_empty(__isl_keep isl_basic_set *bset);
 int isl_basic_set_is_bounded(__isl_keep isl_basic_set *bset);
@@ -234,6 +243,8 @@ __isl_give isl_set *isl_set_project_out(__isl_take isl_set *set,
                enum isl_dim_type type, unsigned first, unsigned n);
 __isl_give isl_basic_set *isl_basic_set_remove_divs(
        __isl_take isl_basic_set *bset);
+__isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set,
+       enum isl_dim_type type, unsigned first, unsigned n);
 struct isl_set *isl_set_eliminate_dims(struct isl_set *set,
                unsigned first, unsigned n);
 __isl_give isl_set *isl_set_remove_dims(__isl_take isl_set *bset,
@@ -245,8 +256,15 @@ __isl_give isl_set *isl_set_remove_divs(__isl_take isl_set *set);
 __isl_give isl_set *isl_set_split_dims(__isl_take isl_set *set,
        enum isl_dim_type type, unsigned first, unsigned n);
 
+int isl_basic_set_involves_dims(__isl_keep isl_basic_set *bset,
+       enum isl_dim_type type, unsigned first, unsigned n);
+int isl_set_involves_dims(__isl_keep isl_set *set,
+       enum isl_dim_type type, unsigned first, unsigned n);
+
 void isl_set_print_internal(__isl_keep isl_set *set, FILE *out, int indent);
+int isl_set_plain_is_empty(__isl_keep isl_set *set);
 int isl_set_fast_is_empty(__isl_keep isl_set *set);
+int isl_set_plain_is_universe(__isl_keep isl_set *set);
 int isl_set_fast_is_universe(__isl_keep isl_set *set);
 int isl_set_is_empty(__isl_keep isl_set *set);
 int isl_set_is_bounded(__isl_keep isl_set *set);
@@ -271,11 +289,14 @@ struct isl_basic_set *isl_set_copy_basic_set(struct isl_set *set);
 struct isl_set *isl_set_drop_basic_set(struct isl_set *set,
                                                struct isl_basic_set *bset);
 
-int isl_basic_set_fast_dim_is_fixed(struct isl_basic_set *bset, unsigned dim,
-       isl_int *val);
+int isl_basic_set_plain_dim_is_fixed(__isl_keep isl_basic_set *bset,
+       unsigned dim, isl_int *val);
 
-int isl_set_fast_dim_is_fixed(struct isl_set *set, unsigned dim, isl_int *val);
-int isl_set_fast_dim_has_fixed_lower_bound(struct isl_set *set,
+int isl_set_plain_dim_is_fixed(__isl_keep isl_set *set,
+       unsigned dim, isl_int *val);
+int isl_set_fast_dim_is_fixed(__isl_keep isl_set *set,
+       unsigned dim, isl_int *val);
+int isl_set_plain_dim_has_fixed_lower_bound(__isl_keep isl_set *set,
        unsigned dim, isl_int *val);
 int isl_set_dim_is_bounded(__isl_keep isl_set *set,
        enum isl_dim_type type, unsigned pos);
@@ -293,8 +314,12 @@ int isl_set_dim_residue_class(struct isl_set *set,
 
 __isl_give isl_set *isl_set_coalesce(__isl_take isl_set *set);
 
+int isl_set_plain_is_equal(__isl_keep isl_set *set1, __isl_keep isl_set *set2);
 int isl_set_fast_is_equal(__isl_keep isl_set *set1, __isl_keep isl_set *set2);
-int isl_set_fast_is_disjoint(__isl_keep isl_set *set1, __isl_keep isl_set *set2);
+int isl_set_plain_is_disjoint(__isl_keep isl_set *set1,
+       __isl_keep isl_set *set2);
+int isl_set_fast_is_disjoint(__isl_keep isl_set *set1,
+       __isl_keep isl_set *set2);
 
 uint32_t isl_set_get_hash(struct isl_set *set);
 
@@ -332,6 +357,9 @@ __isl_give isl_map *isl_set_lex_gt_set(__isl_take isl_set *set1,
 
 int isl_set_size(__isl_keep isl_set *set);
 
+__isl_give isl_set *isl_set_align_params(__isl_take isl_set *set,
+       __isl_take isl_dim *model);
+
 __isl_give isl_mat *isl_basic_set_equalities_matrix(
        __isl_keep isl_basic_set *bset, enum isl_dim_type c1,
        enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4);
@@ -345,6 +373,13 @@ __isl_give isl_basic_set *isl_basic_set_from_constraint_matrices(
 
 __isl_give isl_mat *isl_basic_set_reduced_basis(__isl_keep isl_basic_set *bset);
 
+__isl_give isl_basic_set *isl_basic_set_coefficients(
+       __isl_take isl_basic_set *bset);
+__isl_give isl_basic_set *isl_set_coefficients(__isl_take isl_set *set);
+__isl_give isl_basic_set *isl_basic_set_solutions(
+       __isl_take isl_basic_set *bset);
+__isl_give isl_basic_set *isl_set_solutions(__isl_take isl_set *set);
+
 #if defined(__cplusplus)
 }
 #endif
index bd79494..0478c57 100644 (file)
@@ -24,6 +24,8 @@ void isl_union_map_free(__isl_take isl_union_map *umap);
 isl_ctx *isl_union_map_get_ctx(__isl_keep isl_union_map *umap);
 __isl_give isl_dim *isl_union_map_get_dim(__isl_keep isl_union_map *umap);
 
+__isl_give isl_union_map *isl_union_map_universe(
+       __isl_take isl_union_map *umap);
 __isl_give isl_union_set *isl_union_map_domain(__isl_take isl_union_map *umap);
 __isl_give isl_union_set *isl_union_map_range(__isl_take isl_union_map *umap);
 __isl_give isl_union_map *isl_union_map_domain_map(
@@ -84,6 +86,10 @@ __isl_give isl_union_map *isl_union_map_deltas_map(
 __isl_give isl_union_map *isl_union_set_identity(__isl_take isl_union_set *uset);
 
 int isl_union_map_is_empty(__isl_keep isl_union_map *umap);
+int isl_union_map_is_single_valued(__isl_keep isl_union_map *umap);
+int isl_union_map_plain_is_injective(__isl_keep isl_union_map *umap);
+int isl_union_map_is_injective(__isl_keep isl_union_map *umap);
+int isl_union_map_is_bijective(__isl_keep isl_union_map *umap);
 
 int isl_union_map_is_subset(__isl_keep isl_union_map *umap1,
        __isl_keep isl_union_map *umap2);
@@ -95,8 +101,11 @@ int isl_union_map_is_strict_subset(__isl_keep isl_union_map *umap1,
 int isl_union_map_n_map(__isl_keep isl_union_map *umap);
 int isl_union_map_foreach_map(__isl_keep isl_union_map *umap,
        int (*fn)(__isl_take isl_map *map, void *user), void *user);
+__isl_give int isl_union_map_contains(__isl_keep isl_union_map *umap,
+       __isl_keep isl_dim *dim);
 __isl_give isl_map *isl_union_map_extract_map(__isl_keep isl_union_map *umap,
        __isl_take isl_dim *dim);
+__isl_give isl_map *isl_union_map_copy_map(__isl_keep isl_union_map *umap);
 
 __isl_give isl_basic_map *isl_union_map_sample(__isl_take isl_union_map *umap);
 
index 1be5c27..84b374f 100644 (file)
@@ -16,6 +16,9 @@ void isl_union_set_free(__isl_take isl_union_set *uset);
 isl_ctx *isl_union_set_get_ctx(__isl_keep isl_union_set *uset);
 __isl_give isl_dim *isl_union_set_get_dim(__isl_keep isl_union_set *uset);
 
+__isl_give isl_union_set *isl_union_set_universe(
+       __isl_take isl_union_set *uset);
+
 __isl_give isl_union_set *isl_union_set_detect_equalities(
        __isl_take isl_union_set *uset);
 __isl_give isl_union_set *isl_union_set_affine_hull(
@@ -59,13 +62,18 @@ int isl_union_set_is_strict_subset(__isl_keep isl_union_set *uset1,
 int isl_union_set_n_set(__isl_keep isl_union_set *uset);
 int isl_union_set_foreach_set(__isl_keep isl_union_set *uset,
        int (*fn)(__isl_take isl_set *set, void *user), void *user);
+__isl_give int isl_union_set_contains(__isl_keep isl_union_set *uset,
+       __isl_keep isl_dim *dim);
 __isl_give isl_set *isl_union_set_extract_set(__isl_keep isl_union_set *uset,
        __isl_take isl_dim *dim);
+__isl_give isl_set *isl_union_set_copy_set(__isl_keep isl_union_set *uset);
 int isl_union_set_foreach_point(__isl_keep isl_union_set *uset,
        int (*fn)(__isl_take isl_point *pnt, void *user), void *user);
 
 __isl_give isl_basic_set *isl_union_set_sample(__isl_take isl_union_set *uset);
 
+__isl_give isl_union_set *isl_union_set_lift(__isl_take isl_union_set *uset);
+
 __isl_give isl_union_map *isl_union_set_lex_lt_union_set(
        __isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2);
 __isl_give isl_union_map *isl_union_set_lex_le_union_set(
@@ -75,6 +83,11 @@ __isl_give isl_union_map *isl_union_set_lex_gt_union_set(
 __isl_give isl_union_map *isl_union_set_lex_ge_union_set(
        __isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2);
 
+__isl_give isl_union_set *isl_union_set_coefficients(
+       __isl_take isl_union_set *bset);
+__isl_give isl_union_set *isl_union_set_solutions(
+       __isl_take isl_union_set *bset);
+
 __isl_give isl_union_set *isl_union_set_read_from_file(isl_ctx *ctx,
        FILE *input);
 __isl_give isl_union_set *isl_union_set_read_from_str(struct isl_ctx *ctx,
index b23a698..7757acd 100644 (file)
@@ -38,6 +38,8 @@ struct isl_vec *isl_vec_copy(struct isl_vec *vec);
 struct isl_vec *isl_vec_cow(struct isl_vec *vec);
 void isl_vec_free(struct isl_vec *vec);
 
+isl_ctx *isl_vec_get_ctx(__isl_keep isl_vec *vec);
+
 void isl_vec_dump(__isl_keep isl_vec *vec);
 __isl_give isl_printer *isl_printer_print_vec(__isl_take isl_printer *printer,
        __isl_keep isl_vec *vec);
@@ -52,6 +54,8 @@ __isl_give isl_vec *isl_vec_add(__isl_take isl_vec *vec1,
 __isl_give isl_vec *isl_vec_extend(__isl_take isl_vec *vec, unsigned size);
 __isl_give isl_vec *isl_vec_zero_extend(__isl_take isl_vec *vec, unsigned size);
 
+__isl_give isl_vec *isl_vec_sort(__isl_take isl_vec *vec);
+
 __isl_give isl_vec *isl_vec_read_from_file(isl_ctx *ctx, FILE *input);
 
 #if defined(__cplusplus)
diff --git a/isl_aff.c b/isl_aff.c
new file mode 100644 (file)
index 0000000..cc2dc77
--- /dev/null
+++ b/isl_aff.c
@@ -0,0 +1,427 @@
+/*
+ * 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_dim *isl_aff_get_dim(__isl_keep isl_aff *aff)
+{
+       return aff ? isl_local_space_get_dim(aff->ls) : NULL;
+}
+
+__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 84123aa..7c1c547 100644 (file)
@@ -461,7 +461,7 @@ static struct isl_basic_set *uset_affine_hull_bounded(struct isl_basic_set *bset
        struct isl_tab *tab = NULL;
        unsigned dim;
 
-       if (isl_basic_set_fast_is_empty(bset))
+       if (isl_basic_set_plain_is_empty(bset))
                return bset;
 
        dim = isl_basic_set_n_dim(bset);
@@ -697,7 +697,7 @@ static struct isl_basic_set *affine_hull_with_cone(struct isl_basic_set *bset,
        total = isl_basic_set_total_dim(cone);
        cone_dim = total - cone->n_eq;
 
-       M = isl_mat_sub_alloc(bset->ctx, cone->eq, 0, cone->n_eq, 1, total);
+       M = isl_mat_sub_alloc6(bset->ctx, cone->eq, 0, cone->n_eq, 1, total);
        M = isl_mat_left_hermite(M, 0, &U, &Q);
        if (!M)
                goto error;
@@ -764,7 +764,7 @@ static struct isl_basic_set *uset_affine_hull(struct isl_basic_set *bset)
 {
        struct isl_basic_set *cone;
 
-       if (isl_basic_set_fast_is_empty(bset))
+       if (isl_basic_set_plain_is_empty(bset))
                return bset;
 
        cone = isl_basic_set_recession_cone(isl_basic_set_copy(bset));
index d581f2d..0c1dae7 100644 (file)
--- a/isl_blk.c
+++ b/isl_blk.c
@@ -10,6 +10,9 @@
 #include <isl/blk.h>
 #include <isl_ctx_private.h>
 
+/* The maximal number of cache misses before first element is evicted */
+#define ISL_BLK_MAX_MISS       100
+
 struct isl_blk isl_blk_empty()
 {
        struct isl_blk block;
@@ -36,31 +39,7 @@ int isl_blk_is_error(struct isl_blk block)
        return block.size == -1 && block.data == NULL;
 }
 
-struct isl_blk isl_blk_alloc(struct isl_ctx *ctx, size_t n)
-{
-       int i;
-       struct isl_blk block;
-
-       if (ctx->n_cached) {
-               int best = 0;
-               for (i = 1; ctx->cache[best].size != n && i < ctx->n_cached; ++i) {
-                       if (ctx->cache[best].size < n) {
-                               if (ctx->cache[i].size > ctx->cache[best].size)
-                                       best = i;
-                       } else if (ctx->cache[i].size >= n &&
-                                  ctx->cache[i].size < ctx->cache[best].size)
-                                       best = i;
-               }
-               block = ctx->cache[best];
-               if (--ctx->n_cached != best)
-                       ctx->cache[best] = ctx->cache[ctx->n_cached];
-       } else
-               block = isl_blk_empty();
-
-       return isl_blk_extend(ctx, block, n);
-}
-
-struct isl_blk isl_blk_extend(struct isl_ctx *ctx, struct isl_blk block,
+static struct isl_blk extend(struct isl_ctx *ctx, struct isl_blk block,
                                size_t new_n)
 {
        int i;
@@ -92,6 +71,48 @@ static void isl_blk_free_force(struct isl_ctx *ctx, struct isl_blk block)
        free(block.data);
 }
 
+struct isl_blk isl_blk_alloc(struct isl_ctx *ctx, size_t n)
+{
+       int i;
+       struct isl_blk block;
+
+       block = isl_blk_empty();
+       if (n && ctx->n_cached) {
+               int best = 0;
+               for (i = 1; ctx->cache[best].size != n && i < ctx->n_cached; ++i) {
+                       if (ctx->cache[best].size < n) {
+                               if (ctx->cache[i].size > ctx->cache[best].size)
+                                       best = i;
+                       } else if (ctx->cache[i].size >= n &&
+                                  ctx->cache[i].size < ctx->cache[best].size)
+                                       best = i;
+               }
+               if (ctx->cache[best].size < 2 * n + 100) {
+                       block = ctx->cache[best];
+                       if (--ctx->n_cached != best)
+                               ctx->cache[best] = ctx->cache[ctx->n_cached];
+                       if (best == 0)
+                               ctx->n_miss = 0;
+               } else if (ctx->n_miss++ >= ISL_BLK_MAX_MISS) {
+                       isl_blk_free_force(ctx, ctx->cache[0]);
+                       if (--ctx->n_cached != 0)
+                               ctx->cache[0] = ctx->cache[ctx->n_cached];
+                       ctx->n_miss = 0;
+               }
+       }
+
+       return extend(ctx, block, n);
+}
+
+struct isl_blk isl_blk_extend(struct isl_ctx *ctx, struct isl_blk block,
+                               size_t new_n)
+{
+       if (isl_blk_is_empty(block))
+               return isl_blk_alloc(ctx, new_n);
+
+       return extend(ctx, block, new_n);
+}
+
 void isl_blk_free(struct isl_ctx *ctx, struct isl_blk block)
 {
        if (isl_blk_is_empty(block) || isl_blk_is_error(block))
index 9a8050c..6b3ed93 100644 (file)
 #include <isl_map_private.h>
 #include <isl/constraint.h>
 #include <isl_dim_private.h>
+#include <isl_div_private.h>
 #include <isl/seq.h>
+#include <isl_aff_private.h>
+
+isl_ctx *isl_constraint_get_ctx(__isl_keep isl_constraint *c)
+{
+       return c ? c->ctx : NULL;
+}
 
 static unsigned n(struct isl_constraint *c, enum isl_dim_type type)
 {
@@ -276,6 +283,23 @@ struct isl_basic_set *isl_basic_set_add_constraint(
                                                constraint);
 }
 
+__isl_give isl_map *isl_map_add_constraint(__isl_take isl_map *map,
+       __isl_take isl_constraint *constraint)
+{
+       isl_basic_map *bmap;
+
+       bmap = isl_basic_map_from_constraint(constraint);
+       map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+       return map;
+}
+
+__isl_give isl_set *isl_set_add_constraint(__isl_take isl_set *set,
+       __isl_take isl_constraint *constraint)
+{
+       return isl_map_add_constraint(set, constraint);
+}
+
 struct isl_constraint *isl_constraint_add_div(struct isl_constraint *constraint,
        struct isl_div *div, int *pos)
 {
@@ -306,6 +330,12 @@ error:
        return NULL;
 }
 
+__isl_give isl_dim *isl_constraint_get_dim(
+       __isl_keep isl_constraint *constraint)
+{
+       return constraint ? isl_basic_map_get_dim(constraint->bmap) : NULL;
+}
+
 int isl_constraint_dim(struct isl_constraint *constraint,
        enum isl_dim_type type)
 {
@@ -314,6 +344,24 @@ int isl_constraint_dim(struct isl_constraint *constraint,
        return n(constraint, type);
 }
 
+int isl_constraint_involves_dims(__isl_keep isl_constraint *constraint,
+       enum isl_dim_type type, unsigned first, unsigned n)
+{
+       if (!constraint)
+               return -1;
+
+       if (first + n > isl_basic_set_dim(constraint->bmap, type))
+               isl_die(constraint->ctx, isl_error_invalid,
+                       "index out of bounds", return -1);
+
+       first += isl_basic_map_offset(constraint->bmap, type);
+
+       if (isl_seq_first_non_zero(constraint->line[0] + first, n) >= 0)
+               return 1;
+
+       return 0;
+}
+
 const char *isl_constraint_get_dim_name(__isl_keep isl_constraint *constraint,
        enum isl_dim_type type, unsigned pos)
 {
@@ -935,3 +983,68 @@ error:
        isl_basic_set_free(context);
        return -1;
 }
+
+__isl_give isl_aff *isl_constraint_get_bound(
+       __isl_keep isl_constraint *constraint, enum isl_dim_type type, int pos)
+{
+       isl_aff *aff;
+       isl_local_space *ls;
+
+       if (!constraint)
+               return NULL;
+       if (pos >= isl_basic_set_dim(constraint->bmap, type))
+               isl_die(constraint->ctx, isl_error_invalid,
+                       "index out of bounds", return NULL);
+       if (!isl_basic_map_may_be_set(constraint->bmap))
+               isl_die(constraint->ctx, isl_error_invalid,
+                       "not a set constraint", return NULL);
+
+       pos += offset(constraint, type);
+       if (isl_int_is_zero(constraint->line[0][pos]))
+               isl_die(constraint->ctx, isl_error_invalid,
+                       "constraint does not define a bound on given dimension",
+                       return NULL);
+
+       ls = isl_basic_set_get_local_space(constraint->bmap);
+       aff = isl_aff_alloc(ls);
+       if (!aff)
+               return NULL;
+
+       if (isl_int_is_neg(constraint->line[0][pos]))
+               isl_seq_cpy(aff->v->el + 1, constraint->line[0],
+                           aff->v->size - 1);
+       else
+               isl_seq_neg(aff->v->el + 1, constraint->line[0],
+                           aff->v->size - 1);
+       isl_int_set_si(aff->v->el[1 + pos], 0);
+       isl_int_abs(aff->v->el[0], constraint->line[0][pos]);
+
+       return aff;
+}
+
+/* Construct an equality constraint equating the given affine expression
+ * to zero.
+ */
+__isl_give isl_constraint *isl_equality_from_aff(__isl_take isl_aff *aff)
+{
+       int k;
+       isl_basic_set *bset;
+
+       if (!aff)
+               return NULL;
+
+       bset = isl_basic_set_from_local_space(isl_aff_get_local_space(aff));
+       bset = isl_basic_set_extend_constraints(bset, 1, 0);
+       k = isl_basic_set_alloc_equality(bset);
+       if (k < 0)
+               goto error;
+
+       isl_seq_cpy(bset->eq[k], aff->v->el + 1, aff->v->size - 1);
+       isl_aff_free(aff);
+
+       return isl_basic_set_constraint(bset, &bset->eq[k]);
+error:
+       isl_aff_free(aff);
+       isl_basic_set_free(bset);
+       return NULL;
+}
index b0e3ed9..0bd82e6 100644 (file)
@@ -899,7 +899,7 @@ int isl_basic_set_is_bounded(__isl_keep isl_basic_set *bset)
 
        if (!bset)
                return -1;
-       if (isl_basic_set_fast_is_empty(bset))
+       if (isl_basic_set_plain_is_empty(bset))
                return 1;
 
        tab = isl_tab_from_recession_cone(bset, 1);
@@ -1039,7 +1039,7 @@ static struct isl_basic_set *modulo_lineality(struct isl_set *set,
        if (!set || !lin)
                goto error;
        lin_dim = total - lin->n_eq;
-       M = isl_mat_sub_alloc(set->ctx, lin->eq, 0, lin->n_eq, 1, total);
+       M = isl_mat_sub_alloc6(set->ctx, lin->eq, 0, lin->n_eq, 1, total);
        M = isl_mat_left_hermite(M, 0, &U, &Q);
        if (!M)
                goto error;
@@ -1672,7 +1672,7 @@ static struct isl_basic_set *common_constraints(struct isl_basic_set *hull,
 
        total = isl_dim_total(set->dim);
        for (i = 0; i < set->p[best]->n_ineq; ++i) {
-               constraints[i].c = isl_mat_sub_alloc(hull->ctx,
+               constraints[i].c = isl_mat_sub_alloc6(hull->ctx,
                        set->p[best]->ineq + i, 0, 1, 0, 1 + total);
                if (!constraints[i].c)
                        goto error;
index 4ea7a70..5b37bf5 100644 (file)
--- a/isl_ctx.c
+++ b/isl_ctx.c
@@ -93,6 +93,7 @@ isl_ctx *isl_ctx_alloc_with_options(struct isl_arg *arg, void *user_opt)
        isl_int_init(ctx->normalize_gcd);
 
        ctx->n_cached = 0;
+       ctx->n_miss = 0;
 
        ctx->error = isl_error_none;
 
index 45ff837..a943b24 100644 (file)
@@ -18,6 +18,7 @@ struct isl_ctx {
        isl_int                 normalize_gcd;
 
        int                     n_cached;
+       int                     n_miss;
        struct isl_blk          cache[ISL_BLK_CACHE_SIZE];
        struct isl_hash_table   name_hash;
 
index 841b291..042b1fb 100644 (file)
--- a/isl_dim.c
+++ b/isl_dim.c
@@ -168,6 +168,7 @@ static unsigned n(struct isl_dim *dim, enum isl_dim_type type)
        case isl_dim_param:     return dim->nparam;
        case isl_dim_in:        return dim->n_in;
        case isl_dim_out:       return dim->n_out;
+       case isl_dim_all:       return dim->nparam + dim->n_in + dim->n_out;
        default:                return 0;
        }
 }
@@ -1125,6 +1126,17 @@ int isl_dim_is_named_or_nested(__isl_keep isl_dim *dim, enum isl_dim_type type)
        return 0;
 }
 
+int isl_dim_may_be_set(__isl_keep isl_dim *dim)
+{
+       if (!dim)
+               return -1;
+       if (isl_dim_size(dim, isl_dim_in) != 0)
+               return 0;
+       if (isl_dim_is_named_or_nested(dim, isl_dim_in))
+               return 0;
+       return 1;
+}
+
 __isl_give isl_dim *isl_dim_reset(__isl_take isl_dim *dim,
        enum isl_dim_type type)
 {
@@ -1249,3 +1261,21 @@ error:
        isl_dim_free(dim);
        return NULL;
 }
+
+int isl_dim_has_named_params(__isl_keep isl_dim *dim)
+{
+       int i;
+       unsigned off;
+
+       if (!dim)
+               return -1;
+       if (dim->nparam == 0)
+               return 1;
+       off = isl_dim_offset(dim, isl_dim_param);
+       if (off + dim->nparam > dim->n_name)
+               return 0;
+       for (i = 0; i < dim->nparam; ++i)
+               if (!dim->names[off + i])
+                       return 0;
+       return 1;
+}
diff --git a/isl_dim_map.c b/isl_dim_map.c
new file mode 100644 (file)
index 0000000..ab3d303
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010-2011 INRIA Saclay
+ *
+ * Use of this software is governed by the GNU LGPLv2.1 license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ */
+
+#include <isl_map_private.h>
+#include <isl_dim_private.h>
+#include <isl_dim_map.h>
+#include <isl_reordering.h>
+
+struct isl_dim_map_entry {
+       int pos;
+       int sgn;
+};
+
+/* Maps dst positions to src positions */
+struct isl_dim_map {
+       unsigned len;
+       struct isl_dim_map_entry m[1];
+};
+
+__isl_give isl_dim_map *isl_dim_map_alloc(isl_ctx *ctx, unsigned len)
+{
+       int i;
+       struct isl_dim_map *dim_map;
+       dim_map = isl_alloc(ctx, struct isl_dim_map,
+           sizeof(struct isl_dim_map) + len * sizeof(struct isl_dim_map_entry));
+       if (!dim_map)
+               return NULL;
+       dim_map->len = 1 + len;
+       dim_map->m[0].pos = 0;
+       dim_map->m[0].sgn = 1;
+       for (i = 0; i < len; ++i)
+               dim_map->m[1 + i].sgn = 0;
+       return dim_map;
+}
+
+void isl_dim_map_range(__isl_keep isl_dim_map *dim_map,
+       unsigned dst_pos, unsigned dst_stride,
+       unsigned src_pos, unsigned src_stride,
+       unsigned n, int sign)
+{
+       int i;
+
+       if (!dim_map)
+               return;
+
+       for (i = 0; i < n; ++i) {
+               unsigned d = 1 + dst_pos + dst_stride * i;
+               unsigned s = 1 + src_pos + src_stride * i;
+               dim_map->m[d].pos = s;
+               dim_map->m[d].sgn = sign;
+       }
+}
+
+void isl_dim_map_dim_range(__isl_keep isl_dim_map *dim_map,
+       struct isl_dim *dim, enum isl_dim_type type,
+       unsigned first, unsigned n, unsigned dst_pos)
+{
+       int i;
+       unsigned src_pos;
+
+       if (!dim_map || !dim)
+               return;
+       
+       src_pos = 1 + isl_dim_offset(dim, type);
+       for (i = 0; i < n; ++i) {
+               dim_map->m[1 + dst_pos + i].pos = src_pos + first + i;
+               dim_map->m[1 + dst_pos + i].sgn = 1;
+       }
+}
+
+void isl_dim_map_dim(__isl_keep isl_dim_map *dim_map, __isl_keep isl_dim *dim,
+       enum isl_dim_type type, unsigned dst_pos)
+{
+       isl_dim_map_dim_range(dim_map, dim, type,
+                             0, isl_dim_size(dim, type), dst_pos);
+}
+
+void isl_dim_map_div(__isl_keep isl_dim_map *dim_map,
+       __isl_keep isl_basic_map *bmap, unsigned dst_pos)
+{
+       int i;
+       unsigned src_pos;
+
+       if (!dim_map || !bmap)
+               return;
+       
+       src_pos = 1 + isl_dim_total(bmap->dim);
+       for (i = 0; i < bmap->n_div; ++i) {
+               dim_map->m[1 + dst_pos + i].pos = src_pos + i;
+               dim_map->m[1 + dst_pos + i].sgn = 1;
+       }
+}
+
+void isl_dim_map_dump(struct isl_dim_map *dim_map)
+{
+       int i;
+
+       for (i = 0; i < dim_map->len; ++i)
+               fprintf(stderr, "%d -> %d * %d; ", i,
+                       dim_map->m[i].sgn, dim_map->m[i].pos);
+       fprintf(stderr, "\n");
+}
+
+static void copy_constraint_dim_map(isl_int *dst, isl_int *src,
+                                       struct isl_dim_map *dim_map)
+{
+       int i;
+
+       for (i = 0; i < dim_map->len; ++i) {
+               if (dim_map->m[i].sgn == 0)
+                       isl_int_set_si(dst[i], 0);
+               else if (dim_map->m[i].sgn > 0)
+                       isl_int_set(dst[i], src[dim_map->m[i].pos]);
+               else
+                       isl_int_neg(dst[i], src[dim_map->m[i].pos]);
+       }
+}
+
+static void copy_div_dim_map(isl_int *dst, isl_int *src,
+                                       struct isl_dim_map *dim_map)
+{
+       isl_int_set(dst[0], src[0]);
+       copy_constraint_dim_map(dst+1, src+1, dim_map);
+}
+
+__isl_give isl_basic_map *isl_basic_map_add_constraints_dim_map(
+       __isl_take isl_basic_map *dst, __isl_take isl_basic_map *src,
+       __isl_take isl_dim_map *dim_map)
+{
+       int i;
+
+       if (!src || !dst || !dim_map)
+               goto error;
+
+       for (i = 0; i < src->n_eq; ++i) {
+               int i1 = isl_basic_map_alloc_equality(dst);
+               if (i1 < 0)
+                       goto error;
+               copy_constraint_dim_map(dst->eq[i1], src->eq[i], dim_map);
+       }
+
+       for (i = 0; i < src->n_ineq; ++i) {
+               int i1 = isl_basic_map_alloc_inequality(dst);
+               if (i1 < 0)
+                       goto error;
+               copy_constraint_dim_map(dst->ineq[i1], src->ineq[i], dim_map);
+       }
+
+       for (i = 0; i < src->n_div; ++i) {
+               int i1 = isl_basic_map_alloc_div(dst);
+               if (i1 < 0)
+                       goto error;
+               copy_div_dim_map(dst->div[i1], src->div[i], dim_map);
+       }
+
+       free(dim_map);
+       isl_basic_map_free(src);
+
+       return dst;
+error:
+       free(dim_map);
+       isl_basic_map_free(src);
+       isl_basic_map_free(dst);
+       return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_add_constraints_dim_map(
+       __isl_take isl_basic_set *dst, __isl_take isl_basic_set *src,
+       __isl_take isl_dim_map *dim_map)
+{
+       return isl_basic_map_add_constraints_dim_map(dst, src, dim_map);
+}
+
+/* Extend the given dim_map with mappings for the divs in bmap.
+ */
+__isl_give isl_dim_map *isl_dim_map_extend(__isl_keep isl_dim_map *dim_map,
+       __isl_keep isl_basic_map *bmap)
+{
+       int i;
+       struct isl_dim_map *res;
+       int offset;
+
+       offset = isl_basic_map_offset(bmap, isl_dim_div);
+
+       res = isl_dim_map_alloc(bmap->ctx, dim_map->len - 1 + bmap->n_div);
+       if (!res)
+               return NULL;
+
+       for (i = 0; i < dim_map->len; ++i)
+               res->m[i] = dim_map->m[i];
+       for (i = 0; i < bmap->n_div; ++i) {
+               res->m[dim_map->len + i].pos = offset + i;
+               res->m[dim_map->len + i].sgn = 1;
+       }
+
+       return res;
+}
+
+/* Extract a dim_map from a reordering.
+ * We essentially need to reverse the mapping, and add an offset
+ * of 1 for the constant term.
+ */
+__isl_give isl_dim_map *isl_dim_map_from_reordering(
+       __isl_keep isl_reordering *exp)
+{
+       int i;
+       isl_ctx *ctx;
+       struct isl_dim_map *dim_map;
+
+       if (!exp)
+               return NULL;
+
+       ctx = isl_dim_get_ctx(exp->dim);
+       dim_map = isl_dim_map_alloc(ctx, isl_dim_total(exp->dim));
+       if (!dim_map)
+               return NULL;
+
+       for (i = 0; i < exp->len; ++i) {
+               dim_map->m[1 + exp->pos[i]].pos = 1 + i;
+               dim_map->m[1 + exp->pos[i]].sgn = 1;
+       }
+
+       return dim_map;
+}
diff --git a/isl_dim_map.h b/isl_dim_map.h
new file mode 100644 (file)
index 0000000..0dcdc73
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef ISL_DIM_MAP_H
+#define ISL_DIM_MAP_H
+
+#include <isl/ctx.h>
+#include <isl/dim.h>
+#include <isl/map.h>
+
+struct isl_dim_map;
+typedef struct isl_dim_map isl_dim_map;
+
+__isl_give isl_dim_map *isl_dim_map_alloc(isl_ctx *ctx, unsigned len);
+void isl_dim_map_range(__isl_keep isl_dim_map *dim_map,
+       unsigned dst_pos, unsigned dst_stride,
+       unsigned src_pos, unsigned src_stride,
+       unsigned n, int sign);
+void isl_dim_map_dim_range(__isl_keep isl_dim_map *dim_map,
+       struct isl_dim *dim, enum isl_dim_type type,
+       unsigned first, unsigned n, unsigned dst_pos);
+void isl_dim_map_dim(__isl_keep isl_dim_map *dim_map, __isl_keep isl_dim *dim,
+       enum isl_dim_type type, unsigned dst_pos);
+void isl_dim_map_div(__isl_keep isl_dim_map *dim_map,
+       __isl_keep isl_basic_map *bmap, unsigned dst_pos);
+__isl_give isl_basic_set *isl_basic_set_add_constraints_dim_map(
+       __isl_take isl_basic_set *dst, __isl_take isl_basic_set *src,
+       __isl_take isl_dim_map *dim_map);
+__isl_give isl_basic_map *isl_basic_map_add_constraints_dim_map(
+       __isl_take isl_basic_map *dst, __isl_take isl_basic_map *src,
+       __isl_take isl_dim_map *dim_map);
+
+__isl_give isl_dim_map *isl_dim_map_extend(__isl_keep isl_dim_map *dim_map,
+       __isl_keep isl_basic_map *bmap);
+
+__isl_give isl_dim_map *isl_dim_map_from_reordering(
+       __isl_keep isl_reordering *exp);
+
+#endif
index a8c6007..4f47eeb 100644 (file)
@@ -24,7 +24,9 @@ __isl_give isl_dim *isl_dim_as_set_dim(__isl_take isl_dim *dim);
 
 unsigned isl_dim_offset(__isl_keep isl_dim *dim, enum isl_dim_type type);
 
+int isl_dim_may_be_set(__isl_keep isl_dim *dim);
 int isl_dim_is_named_or_nested(__isl_keep isl_dim *dim, enum isl_dim_type type);
+int isl_dim_has_named_params(__isl_keep isl_dim *dim);
 __isl_give isl_dim *isl_dim_reset(__isl_take isl_dim *dim,
        enum isl_dim_type type);
 __isl_give isl_dim *isl_dim_flatten(__isl_take isl_dim *dim);
index 4694778..d7ca68f 100644 (file)
--- a/isl_div.c
+++ b/isl_div.c
@@ -8,11 +8,16 @@
  */
 
 #include <isl_map_private.h>
-#include <isl/div.h>
+#include <isl_div_private.h>
 #include <isl/map.h>
 #include <isl_dim_private.h>
 #include <isl/seq.h>
 
+isl_ctx *isl_div_get_ctx(__isl_keep isl_div *div)
+{
+       return div ? div->ctx : NULL;
+}
+
 static unsigned n(struct isl_div *d, enum isl_dim_type type)
 {
        struct isl_dim *dim = d->bmap->dim;
diff --git a/isl_div_private.h b/isl_div_private.h
new file mode 100644 (file)
index 0000000..f0a88f9
--- /dev/null
@@ -0,0 +1,10 @@
+#include <isl/div.h>
+#include <isl/map.h>
+
+struct isl_div {
+       int ref;
+       struct isl_ctx *ctx;
+
+       struct isl_basic_map    *bmap;
+       isl_int                 **line;
+};
index 31e3b9c..68d2c89 100644 (file)
@@ -85,7 +85,7 @@ static struct isl_mat *particular_solution(struct isl_mat *B, struct isl_vec *d)
        M = isl_mat_left_hermite(M, 0, &U, NULL);
        if (!M || !U)
                goto error;
-       H = isl_mat_sub_alloc(B->ctx, M->row, 0, B->n_row, 0, B->n_row);
+       H = isl_mat_sub_alloc(M, 0, B->n_row, 0, B->n_row);
        H = isl_mat_lin_to_aff(H);
        C = isl_mat_inverse_product(H, C);
        if (!C)
@@ -98,8 +98,8 @@ static struct isl_mat *particular_solution(struct isl_mat *B, struct isl_vec *d)
        if (i < B->n_row)
                cst = isl_mat_alloc(B->ctx, B->n_row, 0);
        else
-               cst = isl_mat_sub_alloc(C->ctx, C->row, 1, B->n_row, 0, 1);
-       T = isl_mat_sub_alloc(U->ctx, U->row, B->n_row, B->n_col - 1, 0, B->n_row);
+               cst = isl_mat_sub_alloc(C, 1, B->n_row, 0, 1);
+       T = isl_mat_sub_alloc(U, B->n_row, B->n_col - 1, 0, B->n_row);
        cst = isl_mat_product(T, cst);
        isl_mat_free(M);
        isl_mat_free(C);
@@ -184,7 +184,7 @@ static struct isl_mat *parameter_compression_multi(
                                                D, U->row[j][k]);
        }
        A = isl_mat_left_hermite(A, 0, NULL, NULL);
-       T = isl_mat_sub_alloc(A->ctx, A->row, 0, A->n_row, 0, A->n_row);
+       T = isl_mat_sub_alloc(A, 0, A->n_row, 0, A->n_row);
        T = isl_mat_lin_to_aff(T);
        if (!T)
                goto error;
@@ -426,7 +426,7 @@ struct isl_mat *isl_mat_variable_compression(struct isl_mat *B,
                goto error;
 
        dim = B->n_col - 1;
-       H = isl_mat_sub_alloc(B->ctx, B->row, 0, B->n_row, 1, dim);
+       H = isl_mat_sub_alloc(B, 0, B->n_row, 1, dim);
        H = isl_mat_left_hermite(H, 0, &U, T2);
        if (!H || !U || (T2 && !*T2))
                goto error;
@@ -441,7 +441,7 @@ struct isl_mat *isl_mat_variable_compression(struct isl_mat *B,
                goto error;
        isl_int_set_si(C->row[0][0], 1);
        isl_mat_sub_neg(C->ctx, C->row+1, B->row, B->n_row, 0, 0, 1);
-       H1 = isl_mat_sub_alloc(H->ctx, H->row, 0, H->n_row, 0, H->n_row);
+       H1 = isl_mat_sub_alloc(H, 0, H->n_row, 0, H->n_row);
        H1 = isl_mat_lin_to_aff(H1);
        TC = isl_mat_inverse_product(H1, C);
        if (!TC)
@@ -464,10 +464,9 @@ struct isl_mat *isl_mat_variable_compression(struct isl_mat *B,
                }
                isl_int_set_si(TC->row[0][0], 1);
        }
-       U1 = isl_mat_sub_alloc(U->ctx, U->row, 0, U->n_row, 0, B->n_row);
+       U1 = isl_mat_sub_alloc(U, 0, U->n_row, 0, B->n_row);
        U1 = isl_mat_lin_to_aff(U1);
-       U2 = isl_mat_sub_alloc(U->ctx, U->row, 0, U->n_row,
-                               B->n_row, U->n_row - B->n_row);
+       U2 = isl_mat_sub_alloc(U, 0, U->n_row, B->n_row, U->n_row - B->n_row);
        U2 = isl_mat_lin_to_aff(U2);
        isl_mat_free(U);
        TC = isl_mat_product(U1, TC);
@@ -513,7 +512,7 @@ static struct isl_basic_set *compress_variables(
        if (bset->n_eq == 0)
                return bset;
 
-       B = isl_mat_sub_alloc(bset->ctx, bset->eq, 0, bset->n_eq, 0, 1 + dim);
+       B = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq, 0, 1 + dim);
        TC = isl_mat_variable_compression(B, T2);
        if (!TC)
                goto error;
@@ -576,7 +575,7 @@ int isl_basic_set_dim_residue_class(struct isl_basic_set *bset,
        if (!bset || !modulo || !residue)
                return -1;
 
-       if (isl_basic_set_fast_dim_is_fixed(bset, pos, residue)) {
+       if (isl_basic_set_plain_dim_is_fixed(bset, pos, residue)) {
                isl_int_set_si(*modulo, 0);
                return 0;
        }
@@ -584,7 +583,7 @@ int isl_basic_set_dim_residue_class(struct isl_basic_set *bset,
        ctx = bset->ctx;
        total = isl_basic_set_total_dim(bset);
        nparam = isl_basic_set_n_param(bset);
-       H = isl_mat_sub_alloc(bset->ctx, bset->eq, 0, bset->n_eq, 1, total);
+       H = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq, 1, total);
        H = isl_mat_left_hermite(H, 0, &U, NULL);
        if (!H)
                return -1;
@@ -605,11 +604,11 @@ int isl_basic_set_dim_residue_class(struct isl_basic_set *bset,
                goto error;
        isl_int_set_si(C->row[0][0], 1);
        isl_mat_sub_neg(C->ctx, C->row+1, bset->eq, bset->n_eq, 0, 0, 1);
-       H1 = isl_mat_sub_alloc(H->ctx, H->row, 0, H->n_row, 0, H->n_row);
+       H1 = isl_mat_sub_alloc(H, 0, H->n_row, 0, H->n_row);
        H1 = isl_mat_lin_to_aff(H1);
        C = isl_mat_inverse_product(H1, C);
        isl_mat_free(H);
-       U1 = isl_mat_sub_alloc(U->ctx, U->row, nparam+pos, 1, 0, bset->n_eq);
+       U1 = isl_mat_sub_alloc(U, nparam+pos, 1, 0, bset->n_eq);
        U1 = isl_mat_lin_to_aff(U1);
        isl_mat_free(U);
        C = isl_mat_product(U1, C);
diff --git a/isl_farkas.c b/isl_farkas.c
new file mode 100644 (file)
index 0000000..2dc617e
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * Copyright 2010      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_map_private.h>
+#include <isl/set.h>
+#include <isl_dim_private.h>
+#include <isl/seq.h>
+
+/*
+ * Let C be a cone and define
+ *
+ *     C' := { y | forall x in C : y x >= 0 }
+ *
+ * C' contains the coefficients of all linear constraints
+ * that are valid for C.
+ * Furthermore, C'' = C.
+ *
+ * If C is defined as { x | A x >= 0 }
+ * then any element in C' must be a non-negative combination
+ * of the rows of A, i.e., y = t A with t >= 0.  That is,
+ *
+ *     C' = { y | exists t >= 0 : y = t A }
+ *
+ * If any of the rows in A actually represents an equality, then
+ * also negative combinations of this row are allowed and so the
+ * non-negativity constraint on the corresponding element of t
+ * can be dropped.
+ *
+ * A polyhedron P = { x | b + A x >= 0 } can be represented
+ * in homogeneous coordinates by the cone
+ * C = { [z,x] | b z + A x >= and z >= 0 }
+ * The valid linear constraints on C correspond to the valid affine
+ * constraints on P.
+ * This is essentially Farkas' lemma.
+ *
+ * Let A' = [b A], then, since
+ *                               [ 1 0 ]
+ *             [ w y ] = [t_0 t] [ b A ]
+ *
+ * we have
+ *
+ *     C' = { w, y | exists t_0, t >= 0 : y = t A' and w = t_0 + t b }
+ * or
+ *
+ *     C' = { w, y | exists t >= 0 : y = t A' and w - t b >= 0 }
+ *
+ * In practice, we introduce an extra variable (w), shifting all
+ * other variables to the right, and an extra inequality
+ * (w - t b >= 0) corresponding to the positivity constraint on
+ * the homogeneous coordinate.
+ *
+ * When going back from coefficients to solutions, we immediately
+ * plug in 1 for z, which corresponds to shifting all variables
+ * to the left, with the leftmost ending up in the constant position.
+ */
+
+/* Add the given prefix to all named isl_dim_set dimensions in "dim".
+ */
+static __isl_give isl_dim *isl_dim_prefix(__isl_take isl_dim *dim,
+       const char *prefix)
+{
+       int i;
+       isl_ctx *ctx;
+       unsigned nvar;
+       size_t prefix_len = strlen(prefix);
+
+       if (!dim)
+               return NULL;
+
+       ctx = isl_dim_get_ctx(dim);
+       nvar = isl_dim_size(dim, isl_dim_set);
+
+       for (i = 0; i < nvar; ++i) {
+               const char *name;
+               char *prefix_name;
+
+               name = isl_dim_get_name(dim, isl_dim_set, i);
+               if (!name)
+                       continue;
+
+               prefix_name = isl_alloc_array(ctx, char,
+                                             prefix_len + strlen(name) + 1);
+               if (!prefix_name)
+                       goto error;
+               memcpy(prefix_name, prefix, prefix_len);
+               strcpy(prefix_name + prefix_len, name);
+
+               dim = isl_dim_set_name(dim, isl_dim_set, i, prefix_name);
+               free(prefix_name);
+       }
+
+       return dim;
+error:
+       isl_dim_free(dim);
+       return NULL;
+}
+
+/* Given a dimension specification of the solutions space, construct
+ * a dimension specification for the space of coefficients.
+ *
+ * In particular transform
+ *
+ *     [params] -> { S }
+ *
+ * to
+ *
+ *     { coefficients[[cst, params] -> S] }
+ *
+ * and prefix each dimension name with "c_".
+ */
+static __isl_give isl_dim *isl_dim_coefficients(__isl_take isl_dim *dim)
+{
+       isl_dim *dim_param;
+       unsigned nvar;
+       unsigned nparam;
+
+       nvar = isl_dim_size(dim, isl_dim_set);
+       nparam = isl_dim_size(dim, isl_dim_param);
+       dim_param = isl_dim_copy(dim);
+       dim_param = isl_dim_drop(dim_param, isl_dim_set, 0, nvar);
+       dim_param = isl_dim_move(dim_param, isl_dim_set, 0,
+                                isl_dim_param, 0, nparam);
+       dim_param = isl_dim_prefix(dim_param, "c_");
+       dim_param = isl_dim_insert(dim_param, isl_dim_set, 0, 1);
+       dim_param = isl_dim_set_name(dim_param, isl_dim_set, 0, "c_cst");
+       dim = isl_dim_drop(dim, isl_dim_param, 0, nparam);
+       dim = isl_dim_prefix(dim, "c_");
+       dim = isl_dim_join(isl_dim_from_domain(dim_param),
+                          isl_dim_from_range(dim));
+       dim = isl_dim_wrap(dim);
+       dim = isl_dim_set_tuple_name(dim, isl_dim_set, "coefficients");
+
+       return dim;
+}
+
+/* Drop the given prefix from all named dimensions of type "type" in "dim".
+ */
+static __isl_give isl_dim *isl_dim_unprefix(__isl_take isl_dim *dim,
+       enum isl_dim_type type, const char *prefix)
+{
+       int i;
+       unsigned n;
+       size_t prefix_len = strlen(prefix);
+
+       n = isl_dim_size(dim, type);
+
+       for (i = 0; i < n; ++i) {
+               const char *name;
+
+               name = isl_dim_get_name(dim, type, i);
+               if (!name)
+                       continue;
+               if (strncmp(name, prefix, prefix_len))
+                       continue;
+
+               dim = isl_dim_set_name(dim, type, i, name + prefix_len);
+       }
+
+       return dim;
+}
+
+/* Given a dimension specification of the space of coefficients, construct
+ * a dimension specification for the space of solutions.
+ *
+ * In particular transform
+ *
+ *     { coefficients[[cst, params] -> S] }
+ *
+ * to
+ *
+ *     [params] -> { S }
+ *
+ * and drop the "c_" prefix from the dimension names.
+ */
+static __isl_give isl_dim *isl_dim_solutions(__isl_take isl_dim *dim)
+{
+       unsigned nparam;
+
+       dim = isl_dim_unwrap(dim);
+       dim = isl_dim_drop(dim, isl_dim_in, 0, 1);
+       dim = isl_dim_unprefix(dim, isl_dim_in, "c_");
+       dim = isl_dim_unprefix(dim, isl_dim_out, "c_");
+       nparam = isl_dim_size(dim, isl_dim_in);
+       dim = isl_dim_move(dim, isl_dim_param, 0, isl_dim_in, 0, nparam);
+       dim = isl_dim_range(dim);
+
+       return dim;
+}
+
+/* Compute the dual of "bset" by applying Farkas' lemma.
+ * As explained above, we add an extra dimension to represent
+ * the coefficient of the constant term when going from solutions
+ * to coefficients (shift == 1) and we drop the extra dimension when going
+ * in the opposite direction (shift == -1).  "dim" is the space in which
+ * the dual should be created.
+ */
+static __isl_give isl_basic_set *farkas(__isl_take isl_dim *dim,
+       __isl_take isl_basic_set *bset, int shift)
+{
+       int i, j, k;
+       isl_basic_set *dual = NULL;
+       unsigned total;
+
+       total = isl_basic_set_total_dim(bset);
+
+       dual = isl_basic_set_alloc_dim(dim, bset->n_eq + bset->n_ineq,
+                                       total, bset->n_ineq + (shift > 0));
+       dual = isl_basic_set_set_rational(dual);
+
+       for (i = 0; i < bset->n_eq + bset->n_ineq; ++i) {
+               k = isl_basic_set_alloc_div(dual);
+               if (k < 0)
+                       goto error;
+               isl_int_set_si(dual->div[k][0], 0);
+       }
+
+       for (i = 0; i < total; ++i) {
+               k = isl_basic_set_alloc_equality(dual);
+               if (k < 0)
+                       goto error;
+               isl_seq_clr(dual->eq[k], 1 + shift + total);
+               isl_int_set_si(dual->eq[k][1 + shift + i], -1);
+               for (j = 0; j < bset->n_eq; ++j)
+                       isl_int_set(dual->eq[k][1 + shift + total + j],
+                                   bset->eq[j][1 + i]);
+               for (j = 0; j < bset->n_ineq; ++j)
+                       isl_int_set(dual->eq[k][1 + shift + total + bset->n_eq + j],
+                                   bset->ineq[j][1 + i]);
+       }
+
+       for (i = 0; i < bset->n_ineq; ++i) {
+               k = isl_basic_set_alloc_inequality(dual);
+               if (k < 0)
+                       goto error;
+               isl_seq_clr(dual->ineq[k],
+                           1 + shift + total + bset->n_eq + bset->n_ineq);
+               isl_int_set_si(dual->ineq[k][1 + shift + total + bset->n_eq + i], 1);
+       }
+
+       if (shift > 0) {
+               k = isl_basic_set_alloc_inequality(dual);
+               if (k < 0)
+                       goto error;
+               isl_seq_clr(dual->ineq[k], 2 + total);
+               isl_int_set_si(dual->ineq[k][1], 1);
+               for (j = 0; j < bset->n_eq; ++j)
+                       isl_int_neg(dual->ineq[k][2 + total + j],
+                                   bset->eq[j][0]);
+               for (j = 0; j < bset->n_ineq; ++j)
+                       isl_int_neg(dual->ineq[k][2 + total + bset->n_eq + j],
+                                   bset->ineq[j][0]);
+       }
+
+       dual = isl_basic_set_remove_divs(dual);
+       isl_basic_set_simplify(dual);
+       isl_basic_set_finalize(dual);
+
+       isl_basic_set_free(bset);
+       return dual;
+error:
+       isl_basic_set_free(bset);
+       isl_basic_set_free(dual);
+       return NULL;
+}
+
+/* Construct a basic set containing the tuples of coefficients of all
+ * valid affine constraints on the given basic set.
+ */
+__isl_give isl_basic_set *isl_basic_set_coefficients(
+       __isl_take isl_basic_set *bset)
+{
+       isl_dim *dim;
+
+       if (!bset)
+               return NULL;
+       if (bset->n_div)
+               isl_die(bset->ctx, isl_error_invalid,
+                       "input set not allowed to have local variables",
+                       goto error);
+
+       dim = isl_basic_set_get_dim(bset);
+       dim = isl_dim_coefficients(dim);
+
+       return farkas(dim, bset, 1);
+error:
+       isl_basic_set_free(bset);
+       return NULL;
+}
+
+/* Construct a basic set containing the elements that satisfy all
+ * affine constraints whose coefficient tuples are
+ * contained in the given basic set.
+ */
+__isl_give isl_basic_set *isl_basic_set_solutions(
+       __isl_take isl_basic_set *bset)
+{
+       isl_dim *dim;
+
+       if (!bset)
+               return NULL;
+       if (bset->n_div)
+               isl_die(bset->ctx, isl_error_invalid,
+                       "input set not allowed to have local variables",
+                       goto error);
+
+       dim = isl_basic_set_get_dim(bset);
+       dim = isl_dim_solutions(dim);
+
+       return farkas(dim, bset, -1);
+error:
+       isl_basic_set_free(bset);
+       return NULL;
+}
+
+/* Construct a basic set containing the tuples of coefficients of all
+ * valid affine constraints on the given set.
+ */
+__isl_give isl_basic_set *isl_set_coefficients(__isl_take isl_set *set)
+{
+       int i;
+       isl_basic_set *coeff;
+
+       if (!set)
+               return NULL;
+       if (set->n == 0) {
+               isl_dim *dim = isl_set_get_dim(set);
+               dim = isl_dim_coefficients(dim);
+               coeff = isl_basic_set_universe(dim);
+               coeff = isl_basic_set_set_rational(coeff);
+               isl_set_free(set);
+               return coeff;
+       }
+
+       coeff = isl_basic_set_coefficients(isl_basic_set_copy(set->p[0]));
+
+       for (i = 1; i < set->n; ++i) {
+               isl_basic_set *bset, *coeff_i;
+               bset = isl_basic_set_copy(set->p[i]);
+               coeff_i = isl_basic_set_coefficients(bset);
+               coeff = isl_basic_set_intersect(coeff, coeff_i);
+       }
+
+       isl_set_free(set);
+       return coeff;
+}
+
+/* Construct a basic set containing the elements that satisfy all
+ * affine constraints whose coefficient tuples are
+ * contained in the given set.
+ */
+__isl_give isl_basic_set *isl_set_solutions(__isl_take isl_set *set)
+{
+       int i;
+       isl_basic_set *sol;
+
+       if (!set)
+               return NULL;
+       if (set->n == 0) {
+               isl_dim *dim = isl_set_get_dim(set);
+               dim = isl_dim_solutions(dim);
+               sol = isl_basic_set_universe(dim);
+               sol = isl_basic_set_set_rational(sol);
+               isl_set_free(set);
+               return sol;
+       }
+
+       sol = isl_basic_set_solutions(isl_basic_set_copy(set->p[0]));
+
+       for (i = 1; i < set->n; ++i) {
+               isl_basic_set *bset, *sol_i;
+               bset = isl_basic_set_copy(set->p[i]);
+               sol_i = isl_basic_set_solutions(bset);
+               sol = isl_basic_set_intersect(sol, sol_i);
+       }
+
+       isl_set_free(set);
+       return sol;
+}
index 9a269b2..d27937c 100644 (file)
@@ -188,7 +188,7 @@ static int access_sort_cmp(const void *p1, const void *p2)
 
        h1 = isl_map_get_hash(i1->source_map);
        h2 = isl_map_get_hash(i2->source_map);
-       return h1 - h2;
+       return h1 > h2 ? 1 : h1 < h2 ? -1 : 0;
 }
 
 /* Sort the must source accesses in order of increasing number of shared
@@ -311,7 +311,7 @@ int isl_flow_foreach(__isl_keep isl_flow *deps,
                return -1;
 
        for (i = 0; i < deps->n_source; ++i) {
-               if (isl_map_fast_is_empty(deps->dep[i].map))
+               if (isl_map_plain_is_empty(deps->dep[i].map))
                        continue;
                if (fn(isl_map_copy(deps->dep[i].map), deps->dep[i].must,
                                deps->dep[i].data, user) < 0)
@@ -475,7 +475,7 @@ static int intermediate_sources(__isl_keep isl_access_info *acc,
        int k, level;
        int depth = 2 * isl_map_dim(acc->source[j].map, isl_dim_in) + 1;
 
-       if (isl_map_fast_is_empty(temp_rel[j]))
+       if (isl_map_plain_is_empty(temp_rel[j]))
                return 0;
 
        for (k = j - 1; k >= 0; --k) {
@@ -498,7 +498,7 @@ static int intermediate_sources(__isl_keep isl_access_info *acc,
                        copy = isl_map_copy(temp_rel[j]);
                        T = last_later_source(acc, copy, j, sink_level, k,
                                              level, &trest);
-                       if (isl_map_fast_is_empty(T)) {
+                       if (isl_map_plain_is_empty(T)) {
                                isl_set_free(trest);
                                isl_map_free(T);
                                continue;
@@ -588,8 +588,8 @@ static __isl_give isl_map *all_intermediate_sources(
        for (k = 0; k < acc->n_must; ++k) {
                int plevel;
 
-               if (isl_map_fast_is_empty(may_rel[k]) &&
-                   isl_map_fast_is_empty(must_rel[k]))
+               if (isl_map_plain_is_empty(may_rel[k]) &&
+                   isl_map_plain_is_empty(must_rel[k]))
                        continue;
 
                plevel = acc->level_before(acc->source[k].data,
@@ -741,7 +741,7 @@ static __isl_give isl_flow *compute_val_based_dependences(
        maydo = isl_set_empty_like(mustdo);
        if (!mustdo || !maydo)
                goto error;
-       if (isl_set_fast_is_empty(mustdo))
+       if (isl_set_plain_is_empty(mustdo))
                goto done;
 
        must_rel = isl_alloc_array(ctx, struct isl_map *, acc->n_must);
@@ -777,8 +777,8 @@ static __isl_give isl_flow *compute_val_based_dependences(
 
                        intermediate_sources(acc, may_rel, j, level);
 
-                       if (isl_set_fast_is_empty(mustdo) &&
-                           isl_set_fast_is_empty(maydo))
+                       if (isl_set_plain_is_empty(mustdo) &&
+                           isl_set_plain_is_empty(maydo))
                                break;
                }
                for (j = j - 1; j >= 0; --j) {
@@ -828,8 +828,8 @@ static __isl_give isl_flow *compute_val_based_dependences(
                                                             may_rel[j]);
                }
 
-               if (isl_set_fast_is_empty(mustdo) &&
-                   isl_set_fast_is_empty(maydo))
+               if (isl_set_plain_is_empty(mustdo) &&
+                   isl_set_plain_is_empty(maydo))
                        break;
        }
 
@@ -962,7 +962,7 @@ static __isl_give struct isl_sched_info *sched_info_alloc(
                goto error;
 
        for (i = 0; i < n; ++i)
-               info->is_cst[i] = isl_map_fast_is_fixed(map, isl_dim_in, i,
+               info->is_cst[i] = isl_map_plain_is_fixed(map, isl_dim_in, i,
                                                        &info->cst->el[i]);
 
        return info;
index edd3817..8e6191c 100644 (file)
@@ -789,7 +789,7 @@ __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fold(
                                        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_fast_is_empty(common)) {
+                       if (isl_set_plain_is_empty(common)) {
                                isl_set_free(common);
                                continue;
                        }
diff --git a/isl_hmap_map_basic_set.c b/isl_hmap_map_basic_set.c
new file mode 100644 (file)
index 0000000..b303516
--- /dev/null
@@ -0,0 +1,102 @@
+#include <isl_hmap_map_basic_set.h>
+
+struct isl_map_basic_set_pair {
+       isl_map         *key;
+       isl_basic_set   *val;
+};
+
+__isl_give isl_hmap_map_basic_set *isl_hmap_map_basic_set_alloc(isl_ctx *ctx,
+       int min_size)
+{
+       return (isl_hmap_map_basic_set *) isl_hash_table_alloc(ctx, min_size);
+}
+
+static int free_pair(void **entry, void *user)
+{
+       struct isl_map_basic_set_pair *pair = *entry;
+       isl_map_free(pair->key);
+       isl_basic_set_free(pair->val);
+       free(pair);
+       *entry = NULL;
+       return 0;
+}
+
+void isl_hmap_map_basic_set_free(isl_ctx *ctx,
+       __isl_take isl_hmap_map_basic_set *hmap)
+{
+       if (!hmap)
+               return;
+       isl_hash_table_foreach(ctx, &hmap->table, &free_pair, NULL);
+       isl_hash_table_free(ctx, &hmap->table);
+}
+
+static int has_key(const void *entry, const void *key)
+{
+       const struct isl_map_basic_set_pair *pair = entry;
+       isl_map *map = (isl_map *)key;
+
+       return isl_map_plain_is_equal(pair->key, map);
+}
+
+int isl_hmap_map_basic_set_has(isl_ctx *ctx,
+       __isl_keep isl_hmap_map_basic_set *hmap, __isl_keep isl_map *key)
+{
+       uint32_t hash;
+
+       hash = isl_map_get_hash(key);
+       return !!isl_hash_table_find(ctx, &hmap->table, hash, &has_key, key, 0);
+}
+
+__isl_give isl_basic_set *isl_hmap_map_basic_set_get(isl_ctx *ctx,
+       __isl_keep isl_hmap_map_basic_set *hmap, __isl_take isl_map *key)
+{
+       struct isl_hash_table_entry *entry;
+       struct isl_map_basic_set_pair *pair;
+       uint32_t hash;
+
+       hash = isl_map_get_hash(key);
+       entry = isl_hash_table_find(ctx, &hmap->table, hash, &has_key, key, 0);
+       isl_map_free(key);
+
+       if (!entry)
+               return NULL;
+
+       pair = entry->data;
+
+       return isl_basic_set_copy(pair->val);
+}
+
+int isl_hmap_map_basic_set_set(isl_ctx *ctx,
+       __isl_keep isl_hmap_map_basic_set *hmap, __isl_take isl_map *key,
+       __isl_take isl_basic_set *val)
+{
+       struct isl_hash_table_entry *entry;
+       struct isl_map_basic_set_pair *pair;
+       uint32_t hash;
+
+       hash = isl_map_get_hash(key);
+       entry = isl_hash_table_find(ctx, &hmap->table, hash, &has_key, key, 1);
+
+       if (!entry)
+               return -1;
+
+       if (entry->data) {
+               pair = entry->data;
+               isl_basic_set_free(pair->val);
+               pair->val = val;
+               isl_map_free(key);
+               return 0;
+       }
+
+       pair = isl_alloc_type(ctx, struct isl_map_basic_set_pair);
+       if (!pair) {
+               isl_map_free(key);
+               isl_basic_set_free(val);
+               return -1;
+       }
+
+       entry->data = pair;
+       pair->key = key;
+       pair->val = val;
+       return 0;
+}
diff --git a/isl_hmap_map_basic_set.h b/isl_hmap_map_basic_set.h
new file mode 100644 (file)
index 0000000..905791d
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef ISL_HMAP_MAP_BASIC_SET_H
+#define ISL_HMAP_MAP_BASIC_SET_H
+
+#include <isl/hash.h>
+#include <isl/map.h>
+#include <isl/set.h>
+
+struct isl_hmap_map_basic_set {
+       struct isl_hash_table table;
+};
+typedef struct isl_hmap_map_basic_set  isl_hmap_map_basic_set;
+
+__isl_give isl_hmap_map_basic_set *isl_hmap_map_basic_set_alloc( isl_ctx *ctx,
+       int min_size);
+void isl_hmap_map_basic_set_free(isl_ctx *ctx,
+       __isl_take isl_hmap_map_basic_set *hmap);
+
+int isl_hmap_map_basic_set_has(isl_ctx *ctx,
+       __isl_keep isl_hmap_map_basic_set *hmap, __isl_keep isl_map *key);
+__isl_give isl_basic_set *isl_hmap_map_basic_set_get(isl_ctx *ctx,
+       __isl_keep isl_hmap_map_basic_set *hmap, __isl_take isl_map *key);
+int isl_hmap_map_basic_set_set(isl_ctx *ctx,
+       __isl_keep isl_hmap_map_basic_set *hmap, __isl_take isl_map *key,
+       __isl_take isl_basic_set *val);
+
+#endif
index 3d3bb92..ec0fe30 100644 (file)
--- a/isl_ilp.c
+++ b/isl_ilp.c
@@ -13,6 +13,9 @@
 #include "isl_sample.h"
 #include <isl/seq.h>
 #include "isl_equalities.h"
+#include <isl_aff_private.h>
+#include <isl_local_space_private.h>
+#include <isl_mat_private.h>
 
 /* Given a basic set "bset", construct a basic set U such that for
  * each element x in U, the whole unit box positioned at x is inside
@@ -308,7 +311,7 @@ enum isl_lp_result isl_basic_set_solve_ilp(struct isl_basic_set *bset, int max,
 
        isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error);
 
-       if (isl_basic_set_fast_is_empty(bset))
+       if (isl_basic_set_plain_is_empty(bset))
                return isl_lp_empty;
 
        if (bset->n_eq)
@@ -331,3 +334,140 @@ error:
        isl_basic_set_free(bset);
        return isl_lp_error;
 }
+
+static enum isl_lp_result basic_set_opt(__isl_keep isl_basic_set *bset, int max,
+       __isl_keep isl_aff *obj, isl_int *opt)
+{
+       enum isl_lp_result res;
+
+       if (!obj)
+               return isl_lp_error;
+       bset = isl_basic_set_copy(bset);
+       bset = isl_basic_set_underlying_set(bset);
+       res = isl_basic_set_solve_ilp(bset, max, obj->v->el + 1, opt, NULL);
+       isl_basic_set_free(bset);
+       return res;
+}
+
+static __isl_give isl_mat *extract_divs(__isl_keep isl_basic_set *bset)
+{
+       int i;
+       isl_ctx *ctx = isl_basic_set_get_ctx(bset);
+       isl_mat *div;
+
+       div = isl_mat_alloc(ctx, bset->n_div,
+                           1 + 1 + isl_basic_set_total_dim(bset));
+       if (!div)
+               return NULL;
+
+       for (i = 0; i < bset->n_div; ++i)
+               isl_seq_cpy(div->row[i], bset->div[i], div->n_col);
+
+       return div;
+}
+
+enum isl_lp_result isl_basic_set_opt(__isl_keep isl_basic_set *bset, int max,
+       __isl_keep isl_aff *obj, isl_int *opt)
+{
+       int *exp1 = NULL;
+       int *exp2 = NULL;
+       isl_ctx *ctx;
+       isl_mat *bset_div = NULL;
+       isl_mat *div = NULL;
+       enum isl_lp_result res;
+
+       if (!bset || !obj)
+               return isl_lp_error;
+
+       ctx = isl_aff_get_ctx(obj);
+       if (!isl_dim_equal(bset->dim, obj->ls->dim))
+               isl_die(ctx, isl_error_invalid,
+                       "spaces don't match", return isl_lp_error);
+       if (!isl_int_is_one(obj->v->el[0]))
+               isl_die(ctx, isl_error_unsupported,
+                       "expecting integer affine expression",
+                       return isl_lp_error);
+
+       if (bset->n_div == 0 && obj->ls->div->n_row == 0)
+               return basic_set_opt(bset, max, obj, opt);
+
+       bset = isl_basic_set_copy(bset);
+       obj = isl_aff_copy(obj);
+
+       bset_div = extract_divs(bset);
+       exp1 = isl_alloc_array(ctx, int, bset_div->n_row);
+       exp2 = isl_alloc_array(ctx, int, obj->ls->div->n_row);
+       if (!bset_div || !exp1 || !exp2)
+               goto error;
+
+       div = isl_merge_divs(bset_div, obj->ls->div, exp1, exp2);
+
+       bset = isl_basic_set_expand_divs(bset, isl_mat_copy(div), exp1);
+       obj = isl_aff_expand_divs(obj, isl_mat_copy(div), exp2);
+
+       res = basic_set_opt(bset, max, obj, opt);
+
+       isl_mat_free(bset_div);
+       isl_mat_free(div);
+       free(exp1);
+       free(exp2);
+       isl_basic_set_free(bset);
+       isl_aff_free(obj);
+
+       return res;
+error:
+       isl_mat_free(div);
+       isl_mat_free(bset_div);
+       free(exp1);
+       free(exp2);
+       isl_basic_set_free(bset);
+       isl_aff_free(obj);
+       return isl_lp_error;
+}
+
+/* Compute the minimum (maximum if max is set) of the integer affine
+ * expression obj over the points in set and put the result in *opt.
+ */
+enum isl_lp_result isl_set_opt(__isl_keep isl_set *set, int max,
+       __isl_keep isl_aff *obj, isl_int *opt)
+{
+       int i;
+       enum isl_lp_result res;
+       int empty = 1;
+       isl_int opt_i;
+
+       if (!set || !obj)
+               return isl_lp_error;
+       if (set->n == 0)
+               return isl_lp_empty;
+
+       res = isl_basic_set_opt(set->p[0], max, obj, opt);
+       if (res == isl_lp_error || res == isl_lp_unbounded)
+               return res;
+       if (set->n == 1)
+               return res;
+       if (res == isl_lp_ok)
+               empty = 0;
+
+       isl_int_init(opt_i);
+       for (i = 1; i < set->n; ++i) {
+               res = isl_basic_set_opt(set->p[i], max, obj, &opt_i);
+               if (res == isl_lp_error || res == isl_lp_unbounded) {
+                       isl_int_clear(opt_i);
+                       return res;
+               }
+               if (res == isl_lp_ok)
+                       empty = 0;
+               if (isl_int_gt(opt_i, *opt))
+                       isl_int_set(*opt, opt_i);
+       }
+       isl_int_clear(opt_i);
+
+       return empty ? isl_lp_empty : isl_lp_ok;
+}
+
+enum isl_lp_result isl_set_max(__isl_keep isl_set *set,
+       __isl_keep isl_aff *obj, isl_int *opt)
+{
+       return isl_set_opt(set, 1, obj, opt);
+}
diff --git a/isl_local_space.c b/isl_local_space.c
new file mode 100644 (file)
index 0000000..a74ef13
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * 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_map_private.h>
+#include <isl_local_space_private.h>
+#include <isl_dim_private.h>
+#include <isl_mat_private.h>
+#include <isl/seq.h>
+
+isl_ctx *isl_local_space_get_ctx(__isl_keep isl_local_space *ls)
+{
+       return ls ? ls->dim->ctx : NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_dim *dim,
+       __isl_take isl_mat *div)
+{
+       isl_ctx *ctx;
+       isl_local_space *ls = NULL;
+
+       if (!dim)
+               goto error;
+
+       ctx = isl_dim_get_ctx(dim);
+       ls = isl_calloc_type(ctx, struct isl_local_space);
+       if (!ls)
+               goto error;
+
+       ls->ref = 1;
+       ls->dim = dim;
+       ls->div = div;
+
+       return ls;
+error:
+       isl_dim_free(dim);
+       isl_local_space_free(ls);
+       return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_dim *dim,
+       unsigned n_div)
+{
+       isl_ctx *ctx;
+       isl_mat *div;
+       unsigned total;
+
+       if (!dim)
+               return NULL;
+
+       total = isl_dim_total(dim);
+
+       ctx = isl_dim_get_ctx(dim);
+       div = isl_mat_alloc(ctx, n_div, 1 + 1 + total + n_div);
+       return isl_local_space_alloc_div(dim, div);
+}
+
+__isl_give isl_local_space *isl_local_space_from_dim(__isl_take isl_dim *dim)
+{
+       return isl_local_space_alloc(dim, 0);
+}
+
+__isl_give isl_local_space *isl_local_space_copy(__isl_keep isl_local_space *ls)
+{
+       if (!ls)
+               return NULL;
+
+       ls->ref++;
+       return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_dup(__isl_keep isl_local_space *ls)
+{
+       isl_local_space *dup;
+
+       if (!ls)
+               return NULL;
+
+       return isl_local_space_alloc_div(isl_dim_copy(ls->dim),
+                                        isl_mat_copy(ls->div));
+
+}
+
+__isl_give isl_local_space *isl_local_space_cow(__isl_take isl_local_space *ls)
+{
+       if (!ls)
+               return NULL;
+
+       if (ls->ref == 1)
+               return ls;
+       ls->ref--;
+       return isl_local_space_dup(ls);
+}
+
+void *isl_local_space_free(__isl_take isl_local_space *ls)
+{
+       if (!ls)
+               return NULL;
+
+       if (--ls->ref > 0)
+               return NULL;
+
+       isl_dim_free(ls->dim);
+       isl_mat_free(ls->div);
+
+       free(ls);
+
+       return NULL;
+}
+
+int isl_local_space_dim(__isl_keep isl_local_space *ls,
+       enum isl_dim_type type)
+{
+       if (!ls)
+               return 0;
+       if (type == isl_dim_div)
+               return ls->div->n_row;
+       if (type == isl_dim_all)
+               return isl_dim_size(ls->dim, isl_dim_all) + ls->div->n_row;
+       return isl_dim_size(ls->dim, type);
+}
+
+unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
+       enum isl_dim_type type)
+{
+       isl_dim *dim;
+
+       if (!ls)
+               return 0;
+
+       dim = ls->dim;
+       switch (type) {
+       case isl_dim_cst:       return 0;
+       case isl_dim_param:     return 1;
+       case isl_dim_in:        return 1 + dim->nparam;
+       case isl_dim_out:       return 1 + dim->nparam + dim->n_in;
+       case isl_dim_div:       return 1 + dim->nparam + dim->n_in + dim->n_out;
+       default:                return 0;
+       }
+}
+
+const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls,
+       enum isl_dim_type type, unsigned pos)
+{
+       return ls ? isl_dim_get_name(ls->dim, type, pos) : NULL;
+}
+
+__isl_give isl_div *isl_local_space_get_div(__isl_keep isl_local_space *ls,
+       int pos)
+{
+       isl_basic_map *bmap;
+
+       if (!ls)
+               return NULL;
+
+       if (pos < 0 || pos >= ls->div->n_row)
+               isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+                       "index out of bounds", return NULL);
+
+       bmap = isl_basic_map_from_local_space(isl_local_space_copy(ls));
+       return isl_basic_map_div(bmap, pos);
+}
+
+__isl_give isl_dim *isl_local_space_get_dim(__isl_keep isl_local_space *ls)
+{
+       if (!ls)
+               return NULL;
+
+       return isl_dim_copy(ls->dim);
+}
+
+__isl_give isl_local_space *isl_local_space_add_div(
+       __isl_take isl_local_space *ls, __isl_take isl_vec *div)
+{
+       ls = isl_local_space_cow(ls);
+       if (!ls || !div)
+               goto error;
+
+       if (ls->div->n_col != div->size)
+               isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+                       "incompatible dimensions", goto error);
+
+       ls->div = isl_mat_add_zero_cols(ls->div, 1);
+       ls->div = isl_mat_add_rows(ls->div, 1);
+       if (!ls->div)
+               goto error;
+
+       isl_seq_cpy(ls->div->row[ls->div->n_row - 1], div->el, div->size);
+       isl_int_set_si(ls->div->row[ls->div->n_row - 1][div->size], 0);
+
+       isl_vec_free(div);
+       return ls;
+error:
+       isl_local_space_free(ls);
+       isl_vec_free(div);
+       return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_replace_divs(
+       __isl_take isl_local_space *ls, __isl_take isl_mat *div)
+{
+       ls = isl_local_space_cow(ls);
+
+       if (!ls || !div)
+               goto error;
+
+       isl_mat_free(ls->div);
+       ls->div = div;
+       return ls;
+error:
+       isl_mat_free(div);
+       isl_local_space_free(ls);
+       return NULL;
+}
+
+/* Copy row "s" of "src" to row "d" of "dst", applying the expansion
+ * defined by "exp".
+ */
+static void expand_row(__isl_keep isl_mat *dst, int d,
+       __isl_keep isl_mat *src, int s, int *exp)
+{
+       int i;
+       unsigned c = src->n_col - src->n_row;
+
+       isl_seq_cpy(dst->row[d], src->row[s], c);
+       isl_seq_clr(dst->row[d] + c, dst->n_col - c);
+
+       for (i = 0; i < s; ++i)
+               isl_int_set(dst->row[d][c + exp[i]], src->row[s][c + i]);
+}
+
+/* Compare (known) divs.
+ * Return non-zero if at least one of the two divs is unknown.
+ */
+static int cmp_row(__isl_keep isl_mat *div, int i, int j)
+{
+       int li, lj;
+
+       if (isl_int_is_zero(div->row[j][0]))
+               return -1;
+       if (isl_int_is_zero(div->row[i][0]))
+               return 1;
+
+       li = isl_seq_last_non_zero(div->row[i], div->n_col);
+       lj = isl_seq_last_non_zero(div->row[j], div->n_col);
+
+       if (li != lj)
+               return li - lj;
+
+       return isl_seq_cmp(div->row[i], div->row[j], div->n_col);
+}
+
+/* Combine the two lists of divs into a single list.
+ * For each row i in div1, exp1[i] is set to the position of the corresponding
+ * row in the result.  Similarly for div2 and exp2.
+ * This function guarantees
+ *     exp1[i] >= i
+ *     exp1[i+1] > exp1[i]
+ * For optimal merging, the two input list should have been sorted.
+ */
+__isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1,
+       __isl_keep isl_mat *div2, int *exp1, int *exp2)
+{
+       int i, j, k;
+       isl_mat *div = NULL;
+       unsigned d = div1->n_col - div1->n_row;
+
+       div = isl_mat_alloc(div1->ctx, 1 + div1->n_row + div2->n_row,
+                               d + div1->n_row + div2->n_row);
+       if (!div)
+               return NULL;
+
+       for (i = 0, j = 0, k = 0; i < div1->n_row && j < div2->n_row; ++k) {
+               int cmp;
+
+               expand_row(div, k, div1, i, exp1);
+               expand_row(div, k + 1, div2, j, exp2);
+
+               cmp = cmp_row(div, k, k + 1);
+               if (cmp == 0) {
+                       exp1[i++] = k;
+                       exp2[j++] = k;
+               } else if (cmp < 0) {
+                       exp1[i++] = k;
+               } else {
+                       exp2[j++] = k;
+                       isl_seq_cpy(div->row[k], div->row[k + 1], div->n_col);
+               }
+       }
+       for (; i < div1->n_row; ++i, ++k) {
+               expand_row(div, k, div1, i, exp1);
+               exp1[i] = k;
+       }
+       for (; j < div2->n_row; ++j, ++k) {
+               expand_row(div, k, div2, j, exp2);
+               exp2[j] = k;
+       }
+
+       div->n_row = k;
+       div->n_col = d + k;
+
+       return div;
+}
diff --git a/isl_local_space_private.h b/isl_local_space_private.h
new file mode 100644 (file)
index 0000000..b0760ed
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef ISL_LOCAL_SPACE_PRIVATE_H
+#define ISL_LOCAL_SPACE_PRIVATE_H
+
+#include <isl/div.h>
+#include <isl/mat.h>
+#include <isl/local_space.h>
+
+struct isl_local_space {
+       int ref;
+
+       isl_dim *dim;
+       isl_mat *div;
+};
+
+__isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_dim *dim,
+       unsigned n_div);
+
+__isl_give isl_local_space *isl_local_space_add_div(
+       __isl_take isl_local_space *ls, __isl_take isl_vec *div);
+
+__isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1,
+       __isl_keep isl_mat *div2, int *exp1, int *exp2);
+
+unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
+       enum isl_dim_type type);
+
+__isl_give isl_local_space *isl_local_space_replace_divs(
+       __isl_take isl_local_space *ls, __isl_take isl_mat *div);
+
+#endif
index 334f383..0668037 100644 (file)
--- a/isl_map.c
+++ b/isl_map.c
 #include "isl_tab.h"
 #include <isl/vec.h>
 #include <isl_mat_private.h>
-
-/* Maps dst positions to src positions */
-struct isl_dim_map {
-       unsigned len;
-       int pos[1];
-};
-
-static struct isl_dim_map *isl_dim_map_alloc(struct isl_ctx *ctx, unsigned len)
-{
-       int i;
-       struct isl_dim_map *dim_map;
-       dim_map = isl_alloc(ctx, struct isl_dim_map,
-                               sizeof(struct isl_dim_map) + len * sizeof(int));
-       if (!dim_map)
-               return NULL;
-       dim_map->len = 1 + len;
-       dim_map->pos[0] = 0;
-       for (i = 0; i < len; ++i)
-               dim_map->pos[1 + i] = -1;
-       return dim_map;
-}
+#include <isl_dim_map.h>
+#include <isl_local_space_private.h>
 
 static unsigned n(struct isl_dim *dim, enum isl_dim_type type)
 {
@@ -71,50 +52,6 @@ static unsigned pos(struct isl_dim *dim, enum isl_dim_type type)
        }
 }
 
-static void isl_dim_map_dim_range(struct isl_dim_map *dim_map,
-       struct isl_dim *dim, enum isl_dim_type type,
-       unsigned first, unsigned n, unsigned dst_pos)
-{
-       int i;
-       unsigned src_pos;
-
-       if (!dim_map || !dim)
-               return;
-       
-       src_pos = pos(dim, type);
-       for (i = 0; i < n; ++i)
-               dim_map->pos[1 + dst_pos + i] = src_pos + first + i;
-}
-
-static void isl_dim_map_dim(struct isl_dim_map *dim_map, struct isl_dim *dim,
-               enum isl_dim_type type, unsigned dst_pos)
-{
-       isl_dim_map_dim_range(dim_map, dim, type, 0, n(dim, type), dst_pos);
-}
-
-static void isl_dim_map_div(struct isl_dim_map *dim_map,
-               struct isl_basic_map *bmap, unsigned dst_pos)
-{
-       int i;
-       unsigned src_pos;
-
-       if (!dim_map || !bmap)
-               return;
-       
-       src_pos = 1 + isl_dim_total(bmap->dim);
-       for (i = 0; i < bmap->n_div; ++i)
-               dim_map->pos[1 + dst_pos + i] = src_pos + i;
-}
-
-static void isl_dim_map_dump(struct isl_dim_map *dim_map)
-{
-       int i;
-
-       for (i = 0; i < dim_map->len; ++i)
-               fprintf(stderr, "%d -> %d; ", i, dim_map->pos[i]);
-       fprintf(stderr, "\n");
-}
-
 unsigned isl_basic_map_dim(const struct isl_basic_map *bmap,
                                enum isl_dim_type type)
 {
@@ -155,6 +92,12 @@ unsigned isl_basic_map_offset(struct isl_basic_map *bmap,
        }
 }
 
+unsigned isl_basic_set_offset(struct isl_basic_set *bset,
+                                       enum isl_dim_type type)
+{
+       return isl_basic_map_offset(bset, type);
+}
+
 static unsigned map_offset(struct isl_map *map, enum isl_dim_type type)
 {
        return pos(map->dim, type);
@@ -254,6 +197,17 @@ int isl_basic_map_compatible_domain(struct isl_basic_map *bmap,
        return isl_dim_tuple_match(bmap->dim, isl_dim_in, bset->dim, isl_dim_set);
 }
 
+int isl_map_compatible_range(__isl_keep isl_map *map, __isl_keep isl_set *set)
+{
+       int m;
+       if (!map || !set)
+               return -1;
+       m = isl_dim_match(map->dim, isl_dim_param, set->dim, isl_dim_param);
+       if (m < 0 || !m)
+               return m;
+       return isl_dim_tuple_match(map->dim, isl_dim_out, set->dim, isl_dim_set);
+}
+
 int isl_basic_map_compatible_range(struct isl_basic_map *bmap,
                struct isl_basic_set *bset)
 {
@@ -300,6 +254,71 @@ struct isl_dim *isl_basic_set_get_dim(struct isl_basic_set *bset)
        return isl_dim_copy(bset->dim);
 }
 
+__isl_give isl_local_space *isl_basic_map_get_local_space(
+       __isl_keep isl_basic_map *bmap)
+{
+       int i;
+       isl_local_space *ls;
+       unsigned total;
+
+       if (!bmap)
+               return NULL;
+
+       total = isl_basic_map_total_dim(bmap);
+       ls = isl_local_space_alloc(isl_dim_copy(bmap->dim), bmap->n_div);
+       if (!ls)
+               return NULL;
+
+       for (i = 0; i < bmap->n_div; ++i)
+               isl_seq_cpy(ls->div->row[i], bmap->div[i], 2 + total);
+
+       return ls;
+}
+
+__isl_give isl_local_space *isl_basic_set_get_local_space(
+       __isl_keep isl_basic_set *bset)
+{
+       return isl_basic_map_get_local_space(bset);
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_local_space(
+       __isl_take isl_local_space *ls)
+{
+       int i;
+       int n_div;
+       isl_basic_map *bmap;
+
+       if (!ls)
+               return NULL;
+
+       n_div = isl_local_space_dim(ls, isl_dim_div);
+       bmap = isl_basic_map_alloc_dim(isl_local_space_get_dim(ls),
+                                       n_div, 0, 2 * n_div);
+
+       for (i = 0; i < n_div; ++i)
+               if (isl_basic_map_alloc_div(bmap) < 0)
+                       goto error;
+
+       for (i = 0; i < n_div; ++i) {
+               isl_seq_cpy(bmap->div[i], ls->div->row[i], ls->div->n_col);
+               if (isl_basic_map_add_div_constraints(bmap, i) < 0)
+                       goto error;
+       }
+                                       
+       isl_local_space_free(ls);
+       return bmap;
+error:
+       isl_local_space_free(ls);
+       isl_basic_map_free(bmap);
+       return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_from_local_space(
+       __isl_take isl_local_space *ls)
+{
+       return isl_basic_map_from_local_space(ls);
+}
+
 struct isl_dim *isl_map_get_dim(struct isl_map *map)
 {
        if (!map)
@@ -1033,66 +1052,6 @@ error:
        return NULL;
 }
 
-static void copy_constraint_dim_map(isl_int *dst, isl_int *src,
-                                       struct isl_dim_map *dim_map)
-{
-       int i;
-
-       for (i = 0; i < dim_map->len; ++i) {
-               if (dim_map->pos[i] < 0)
-                       isl_int_set_si(dst[i], 0);
-               else
-                       isl_int_set(dst[i], src[dim_map->pos[i]]);
-       }
-}
-
-static void copy_div_dim_map(isl_int *dst, isl_int *src,
-                                       struct isl_dim_map *dim_map)
-{
-       isl_int_set(dst[0], src[0]);
-       copy_constraint_dim_map(dst+1, src+1, dim_map);
-}
-
-static struct isl_basic_map *add_constraints_dim_map(struct isl_basic_map *dst,
-               struct isl_basic_map *src, struct isl_dim_map *dim_map)
-{
-       int i;
-
-       if (!src || !dst || !dim_map)
-               goto error;
-
-       for (i = 0; i < src->n_eq; ++i) {
-               int i1 = isl_basic_map_alloc_equality(dst);
-               if (i1 < 0)
-                       goto error;
-               copy_constraint_dim_map(dst->eq[i1], src->eq[i], dim_map);
-       }
-
-       for (i = 0; i < src->n_ineq; ++i) {
-               int i1 = isl_basic_map_alloc_inequality(dst);
-               if (i1 < 0)
-                       goto error;
-               copy_constraint_dim_map(dst->ineq[i1], src->ineq[i], dim_map);
-       }
-
-       for (i = 0; i < src->n_div; ++i) {
-               int i1 = isl_basic_map_alloc_div(dst);
-               if (i1 < 0)
-                       goto error;
-               copy_div_dim_map(dst->div[i1], src->div[i], dim_map);
-       }
-
-       free(dim_map);
-       isl_basic_map_free(src);
-
-       return dst;
-error:
-       free(dim_map);
-       isl_basic_map_free(src);
-       isl_basic_map_free(dst);
-       return NULL;
-}
-
 struct isl_basic_set *isl_basic_set_add_constraints(struct isl_basic_set *bset1,
                struct isl_basic_set *bset2, unsigned pos)
 {
@@ -1459,30 +1418,35 @@ __isl_give isl_basic_set *isl_basic_set_remove_divs(
                        (struct isl_basic_map *)bset);
 }
 
-struct isl_set *isl_set_remove_divs(struct isl_set *set)
+__isl_give isl_map *isl_map_remove_divs(__isl_take isl_map *map)
 {
        int i;
 
-       if (!set)
+       if (!map)
                return NULL;
-       if (set->n == 0)
-               return set;
+       if (map->n == 0)
+               return map;
 
-       set = isl_set_cow(set);
-       if (!set)
+       map = isl_map_cow(map);
+       if (!map)
                return NULL;
        
-       for (i = 0; i < set->n; ++i) {
-               set->p[i] = isl_basic_set_remove_divs(set->p[i]);
-               if (!set->p[i])
+       for (i = 0; i < map->n; ++i) {
+               map->p[i] = isl_basic_map_remove_divs(map->p[i]);
+               if (!map->p[i])
                        goto error;
        }
-       return set;
+       return map;
 error:
-       isl_set_free(set);
+       isl_map_free(map);
        return NULL;
 }
 
+__isl_give isl_set *isl_set_remove_divs(__isl_take isl_set *set)
+{
+       return isl_map_remove_divs(set);
+}
+
 struct isl_basic_map *isl_basic_map_remove_dims(struct isl_basic_map *bmap,
        enum isl_dim_type type, unsigned first, unsigned n)
 {
@@ -1589,6 +1553,51 @@ __isl_give isl_set *isl_set_remove_divs_involving_dims(__isl_take isl_set *set,
                                                              type, first, n);
 }
 
+int isl_basic_set_involves_dims(__isl_keep isl_basic_set *bset,
+       enum isl_dim_type type, unsigned first, unsigned n)
+{
+       int i;
+
+       if (!bset)
+               return -1;
+
+       if (first + n > isl_basic_set_dim(bset, type))
+               isl_die(bset->ctx, isl_error_invalid,
+                       "index out of bounds", return -1);
+
+       first += isl_basic_set_offset(bset, type);
+       for (i = 0; i < bset->n_eq; ++i)
+               if (isl_seq_first_non_zero(bset->eq[i] + first, n) >= 0)
+                       return 1;
+       for (i = 0; i < bset->n_ineq; ++i)
+               if (isl_seq_first_non_zero(bset->ineq[i] + first, n) >= 0)
+                       return 1;
+
+       return 0;
+}
+
+int isl_set_involves_dims(__isl_keep isl_set *set,
+       enum isl_dim_type type, unsigned first, unsigned n)
+{
+       int i;
+
+       if (!set)
+               return -1;
+
+       if (first + n > isl_set_dim(set, type))
+               isl_die(set->ctx, isl_error_invalid,
+                       "index out of bounds", return -1);
+
+       for (i = 0; i < set->n; ++i) {
+               int involves = isl_basic_set_involves_dims(set->p[i],
+                                                           type, first, n);
+               if (involves < 0 || !involves)
+                       return involves;
+       }
+
+       return 1;
+}
+
 /* Return true if the definition of the given div is unknown or depends
  * on unknown divs.
  */
@@ -2086,6 +2095,11 @@ struct isl_basic_map *isl_basic_map_intersect_range(
                isl_assert(bset->ctx,
                    isl_basic_map_compatible_range(bmap, bset), goto error);
 
+       if (isl_basic_set_is_universe(bset)) {
+               isl_basic_set_free(bset);
+               return bmap;
+       }
+
        bmap = isl_basic_map_cow(bmap);
        if (!bmap)
                goto error;
@@ -2228,7 +2242,7 @@ static __isl_give isl_map *map_intersect_add_constraint(
        map1 = isl_map_cow(map1);
        if (!map1)
                goto error;
-       if (isl_map_fast_is_empty(map1)) {
+       if (isl_map_plain_is_empty(map1)) {
                isl_map_free(map2);
                return map1;
        }
@@ -2244,7 +2258,7 @@ static __isl_give isl_map *map_intersect_add_constraint(
        if (!map1->p[0])
                goto error;
 
-       if (isl_basic_map_fast_is_empty(map1->p[0])) {
+       if (isl_basic_map_plain_is_empty(map1->p[0])) {
                isl_basic_map_free(map1->p[0]);
                map1->n = 0;
        }
@@ -2267,11 +2281,11 @@ struct isl_map *isl_map_intersect(struct isl_map *map1, struct isl_map *map2)
        if (!map1 || !map2)
                goto error;
 
-       if (isl_map_fast_is_empty(map1)) {
+       if (isl_map_plain_is_empty(map1)) {
                isl_map_free(map2);
                return map1;
        }
-       if (isl_map_fast_is_empty(map2)) {
+       if (isl_map_plain_is_empty(map2)) {
                isl_map_free(map1);
                return map2;
        }
@@ -2386,7 +2400,7 @@ __isl_give isl_basic_map *isl_basic_map_insert(__isl_take isl_basic_map *bmap,
                        bmap->n_div, bmap->n_eq, bmap->n_ineq);
        if (isl_basic_map_is_rational(bmap))
                res = isl_basic_map_set_rational(res);
-       res = add_constraints_dim_map(res, bmap, dim_map);
+       res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
        return isl_basic_map_finalize(res);
 }
 
@@ -2538,7 +2552,7 @@ __isl_give isl_basic_map *isl_basic_map_move_dims(
 
        res = isl_basic_map_alloc_dim(isl_basic_map_get_dim(bmap),
                        bmap->n_div, bmap->n_eq, bmap->n_ineq);
-       bmap = add_constraints_dim_map(res, bmap, dim_map);
+       bmap = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
 
        bmap->dim = isl_dim_move(bmap->dim, dst_type, dst_pos,
                                        src_type, src_pos, n);
@@ -2659,7 +2673,7 @@ static __isl_give isl_basic_map *move_last(__isl_take isl_basic_map *bmap,
 
        res = isl_basic_map_alloc_dim(isl_basic_map_get_dim(bmap),
                        bmap->n_div, bmap->n_eq, bmap->n_ineq);
-       res = add_constraints_dim_map(res, bmap, dim_map);
+       res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
        return res;
 }
 
@@ -2830,8 +2844,8 @@ struct isl_basic_map *isl_basic_map_apply_range(
                        bmap1->n_div + bmap2->n_div + n,
                        bmap1->n_eq + bmap2->n_eq,
                        bmap1->n_ineq + bmap2->n_ineq);
-       bmap = add_constraints_dim_map(bmap, bmap1, dim_map1);
-       bmap = add_constraints_dim_map(bmap, bmap2, dim_map2);
+       bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+       bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
        bmap = add_divs(bmap, n);
        bmap = isl_basic_map_simplify(bmap);
        bmap = isl_basic_map_drop_redundant_divs(bmap);
@@ -2926,8 +2940,8 @@ struct isl_basic_map *isl_basic_map_sum(
                isl_int_set_si(bmap->eq[j][1+pos+i], 1);
                isl_int_set_si(bmap->eq[j][1+pos-n_out+i], 1);
        }
-       bmap = add_constraints_dim_map(bmap, bmap1, dim_map1);
-       bmap = add_constraints_dim_map(bmap, bmap2, dim_map2);
+       bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+       bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
        bmap = add_divs(bmap, 2 * n_out);
 
        bmap = isl_basic_map_simplify(bmap);
@@ -3069,7 +3083,7 @@ struct isl_basic_map *isl_basic_map_floordiv(struct isl_basic_map *bmap,
        result = isl_basic_map_alloc_dim(isl_dim_copy(bmap->dim),
                        bmap->n_div + n_out,
                        bmap->n_eq, bmap->n_ineq + 2 * n_out);
-       result = add_constraints_dim_map(result, bmap, dim_map);
+       result = isl_basic_map_add_constraints_dim_map(result, bmap, dim_map);
        result = add_divs(result, n_out);
        for (i = 0; i < n_out; ++i) {
                int j;
@@ -3836,8 +3850,19 @@ struct isl_basic_set *isl_basic_map_domain(struct isl_basic_map *bmap)
        return domain;
 }
 
+int isl_basic_map_may_be_set(__isl_keep isl_basic_map *bmap)
+{
+       if (!bmap)
+               return -1;
+       return isl_dim_may_be_set(bmap->dim);
+}
+
 struct isl_basic_set *isl_basic_map_range(struct isl_basic_map *bmap)
 {
+       if (!bmap)
+               return NULL;
+       if (isl_basic_map_may_be_set(bmap))
+               return bmap;
        return isl_basic_map_domain(isl_basic_map_reverse(bmap));
 }
 
@@ -3919,6 +3944,13 @@ error:
        return NULL;
 }
 
+int isl_map_may_be_set(__isl_keep isl_map *map)
+{
+       if (!map)
+               return -1;
+       return isl_dim_may_be_set(map->dim);
+}
+
 struct isl_set *isl_map_range(struct isl_map *map)
 {
        int i;
@@ -3926,8 +3958,7 @@ struct isl_set *isl_map_range(struct isl_map *map)
 
        if (!map)
                goto error;
-       if (isl_map_dim(map, isl_dim_in) == 0 &&
-           !isl_dim_is_named_or_nested(map->dim, isl_dim_in))
+       if (isl_map_may_be_set(map))
                return (isl_set *)map;
 
        map = isl_map_cow(map);
@@ -4328,7 +4359,7 @@ __isl_give isl_map *isl_map_add_basic_map(__isl_take isl_map *map,
 {
        if (!bmap || !map)
                goto error;
-       if (isl_basic_map_fast_is_empty(bmap)) {
+       if (isl_basic_map_plain_is_empty(bmap)) {
                isl_basic_map_free(bmap);
                return map;
        }
@@ -4748,7 +4779,7 @@ static __isl_give isl_map *basic_map_partial_lexopt(
        if (!dom)
                goto error;
 
-       if (isl_set_fast_is_empty(dom)) {
+       if (isl_set_plain_is_empty(dom)) {
                res = isl_map_empty_like_basic_map(bmap);
                *empty = isl_set_empty_like(dom);
                isl_set_free(dom);
@@ -4844,7 +4875,7 @@ static __isl_give isl_map *isl_map_partial_lexopt(
        if (!map || !dom)
                goto error;
 
-       if (isl_map_fast_is_empty(map)) {
+       if (isl_map_plain_is_empty(map)) {
                if (empty)
                        *empty = dom;
                else
@@ -5186,7 +5217,7 @@ static struct isl_set *parameter_compute_divs(struct isl_basic_set *bset)
        if (i == bset->n_eq)
                return isl_basic_set_lexmin(bset);
 
-       eq = isl_mat_sub_alloc(bset->ctx, bset->eq, i, bset->n_eq - i,
+       eq = isl_mat_sub_alloc6(bset->ctx, bset->eq, i, bset->n_eq - i,
                0, 1 + nparam);
        eq = isl_mat_cow(eq);
        T = isl_mat_variable_compression(isl_mat_copy(eq), &T2);
@@ -5472,6 +5503,20 @@ struct isl_map *isl_map_intersect_range(
        if (!map || !set)
                goto error;
 
+       if (!isl_dim_match(map->dim, isl_dim_param, set->dim, isl_dim_param))
+               isl_die(set->ctx, isl_error_invalid,
+                       "parameters don't match", goto error);
+
+       if (isl_dim_size(set->dim, isl_dim_set) != 0 &&
+           !isl_map_compatible_range(map, set))
+               isl_die(set->ctx, isl_error_invalid,
+                       "incompatible spaces", goto error);
+
+       if (isl_set_plain_is_universe(set)) {
+               isl_set_free(set);
+               return map;
+       }
+
        if (ISL_F_ISSET(map, ISL_MAP_DISJOINT) &&
            ISL_F_ISSET(set, ISL_MAP_DISJOINT))
                ISL_FL_SET(flags, ISL_MAP_DISJOINT);
@@ -5897,7 +5942,7 @@ static int foreach_orthant(__isl_take isl_set *set, int *signs, int first,
 
        if (!set)
                return -1;
-       if (isl_set_fast_is_empty(set)) {
+       if (isl_set_plain_is_empty(set)) {
                isl_set_free(set);
                return 0;
        }
@@ -5937,7 +5982,7 @@ int isl_set_foreach_orthant(__isl_keep isl_set *set,
 
        if (!set)
                return -1;
-       if (isl_set_fast_is_empty(set))
+       if (isl_set_plain_is_empty(set))
                return 0;
 
        nparam = isl_set_dim(set, isl_dim_param);
@@ -6017,16 +6062,26 @@ int isl_map_is_empty(struct isl_map *map)
        return 1;
 }
 
-int isl_map_fast_is_empty(struct isl_map *map)
+int isl_map_plain_is_empty(__isl_keep isl_map *map)
 {
        return map ? map->n == 0 : -1;
 }
 
-int isl_set_fast_is_empty(struct isl_set *set)
+int isl_map_fast_is_empty(__isl_keep isl_map *map)
+{
+       return isl_map_plain_is_empty(map);
+}
+
+int isl_set_plain_is_empty(struct isl_set *set)
 {
        return set ? set->n == 0 : -1;
 }
 
+int isl_set_fast_is_empty(__isl_keep isl_set *set)
+{
+       return isl_set_plain_is_empty(set);
+}
+
 int isl_set_is_empty(struct isl_set *set)
 {
        return isl_map_is_empty((struct isl_map *)set);
@@ -6111,7 +6166,7 @@ int isl_basic_set_is_universe(struct isl_basic_set *bset)
        return bset->n_eq == 0 && bset->n_ineq == 0;
 }
 
-int isl_map_fast_is_universe(__isl_keep isl_map *map)
+int isl_map_plain_is_universe(__isl_keep isl_map *map)
 {
        int i;
 
@@ -6127,9 +6182,14 @@ int isl_map_fast_is_universe(__isl_keep isl_map *map)
        return 0;
 }
 
+int isl_set_plain_is_universe(__isl_keep isl_set *set)
+{
+       return isl_map_plain_is_universe((isl_map *) set);
+}
+
 int isl_set_fast_is_universe(__isl_keep isl_set *set)
 {
-       return isl_map_fast_is_universe((isl_map *) set);
+       return isl_set_plain_is_universe(set);
 }
 
 int isl_basic_map_is_empty(struct isl_basic_map *bmap)
@@ -6178,20 +6238,30 @@ int isl_basic_map_is_empty(struct isl_basic_map *bmap)
        return empty;
 }
 
-int isl_basic_map_fast_is_empty(struct isl_basic_map *bmap)
+int isl_basic_map_plain_is_empty(__isl_keep isl_basic_map *bmap)
 {
        if (!bmap)
                return -1;
        return ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY);
 }
 
-int isl_basic_set_fast_is_empty(struct isl_basic_set *bset)
+int isl_basic_map_fast_is_empty(__isl_keep isl_basic_map *bmap)
+{
+       return isl_basic_map_plain_is_empty(bmap);
+}
+
+int isl_basic_set_plain_is_empty(__isl_keep isl_basic_set *bset)
 {
        if (!bset)
                return -1;
        return ISL_F_ISSET(bset, ISL_BASIC_SET_EMPTY);
 }
 
+int isl_basic_set_fast_is_empty(__isl_keep isl_basic_set *bset)
+{
+       return isl_basic_set_plain_is_empty(bset);
+}
+
 int isl_basic_set_is_empty(struct isl_basic_set *bset)
 {
        return isl_basic_map_is_empty((struct isl_basic_map *)bset);
@@ -6276,6 +6346,54 @@ error:
        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_basic_set *isl_basic_set_expand_divs(
+       __isl_take isl_basic_set *bset, __isl_take isl_mat *div, int *exp)
+{
+       int i, j;
+       int n_div;
+
+       bset = isl_basic_set_cow(bset);
+       if (!bset || !div)
+               goto error;
+
+       if (div->n_row < bset->n_div)
+               isl_die(isl_mat_get_ctx(div), isl_error_invalid,
+                       "not an expansion", goto error);
+
+       bset = isl_basic_map_extend_dim(bset, isl_dim_copy(bset->dim),
+                                       div->n_row - bset->n_div, 0,
+                                       2 * (div->n_row - bset->n_div));
+
+       n_div = bset->n_div;
+       for (i = n_div; i < div->n_row; ++i)
+               if (isl_basic_set_alloc_div(bset) < 0)
+                       goto error;
+
+       j = n_div - 1;
+       for (i = div->n_row - 1; i >= 0; --i) {
+               if (j >= 0 && exp[j] == i) {
+                       if (i != j)
+                               isl_basic_map_swap_div(bset, i, j);
+                       j--;
+               } else {
+                       isl_seq_cpy(bset->div[i], div->row[i], div->n_col);
+                       if (isl_basic_map_add_div_constraints(bset, i) < 0)
+                               goto error;
+               }
+       }
+
+       isl_mat_free(div);
+       return bset;
+error:
+       isl_basic_set_free(bset);
+       isl_mat_free(div);
+       return NULL;
+}
+
 /* Look for a div in dst that corresponds to the div "div" in src.
  * The divs before "div" in src and dst are assumed to be the same.
  * 
@@ -6630,7 +6748,7 @@ int isl_set_follows_at(__isl_keep isl_set *set1,
        return follows;
 }
 
-static int isl_basic_map_fast_has_fixed_var(struct isl_basic_map *bmap,
+static int isl_basic_map_plain_has_fixed_var(__isl_keep isl_basic_map *bmap,
        unsigned pos, isl_int *val)
 {
        int i;
@@ -6659,7 +6777,7 @@ static int isl_basic_map_fast_has_fixed_var(struct isl_basic_map *bmap,
        return 0;
 }
 
-static int isl_map_fast_has_fixed_var(struct isl_map *map,
+static int isl_map_plain_has_fixed_var(__isl_keep isl_map *map,
        unsigned pos, isl_int *val)
 {
        int i;
@@ -6672,12 +6790,12 @@ static int isl_map_fast_has_fixed_var(struct isl_map *map,
        if (map->n == 0)
                return 0;
        if (map->n == 1)
-               return isl_basic_map_fast_has_fixed_var(map->p[0], pos, val); 
+               return isl_basic_map_plain_has_fixed_var(map->p[0], pos, val); 
        isl_int_init(v);
        isl_int_init(tmp);
-       fixed = isl_basic_map_fast_has_fixed_var(map->p[0], pos, &v); 
+       fixed = isl_basic_map_plain_has_fixed_var(map->p[0], pos, &v); 
        for (i = 1; fixed == 1 && i < map->n; ++i) {
-               fixed = isl_basic_map_fast_has_fixed_var(map->p[i], pos, &tmp); 
+               fixed = isl_basic_map_plain_has_fixed_var(map->p[i], pos, &tmp); 
                if (fixed == 1 && isl_int_ne(tmp, v))
                        fixed = 0;
        }
@@ -6688,68 +6806,82 @@ static int isl_map_fast_has_fixed_var(struct isl_map *map,
        return fixed;
 }
 
-static int isl_basic_set_fast_has_fixed_var(struct isl_basic_set *bset,
+static int isl_basic_set_plain_has_fixed_var(__isl_keep isl_basic_set *bset,
        unsigned pos, isl_int *val)
 {
-       return isl_basic_map_fast_has_fixed_var((struct isl_basic_map *)bset,
+       return isl_basic_map_plain_has_fixed_var((struct isl_basic_map *)bset,
                                                pos, val);
 }
 
-static int isl_set_fast_has_fixed_var(struct isl_set *set, unsigned pos,
+static int isl_set_plain_has_fixed_var(__isl_keep isl_set *set, unsigned pos,
        isl_int *val)
 {
-       return isl_map_fast_has_fixed_var((struct isl_map *)set, pos, val);
+       return isl_map_plain_has_fixed_var((struct isl_map *)set, pos, val);
 }
 
-int isl_basic_map_fast_is_fixed(struct isl_basic_map *bmap,
+int isl_basic_map_plain_is_fixed(__isl_keep isl_basic_map *bmap,
        enum isl_dim_type type, unsigned pos, isl_int *val)
 {
        if (pos >= isl_basic_map_dim(bmap, type))
                return -1;
-       return isl_basic_map_fast_has_fixed_var(bmap,
+       return isl_basic_map_plain_has_fixed_var(bmap,
                isl_basic_map_offset(bmap, type) - 1 + pos, val);
 }
 
-int isl_map_fast_is_fixed(struct isl_map *map,
+int isl_map_plain_is_fixed(__isl_keep isl_map *map,
        enum isl_dim_type type, unsigned pos, isl_int *val)
 {
        if (pos >= isl_map_dim(map, type))
                return -1;
-       return isl_map_fast_has_fixed_var(map,
+       return isl_map_plain_has_fixed_var(map,
                map_offset(map, type) - 1 + pos, val);
 }
 
+int isl_map_fast_is_fixed(__isl_keep isl_map *map,
+       enum isl_dim_type type, unsigned pos, isl_int *val)
+{
+       return isl_map_plain_is_fixed(map, type, pos, val);
+}
+
 /* Check if dimension dim has fixed value and if so and if val is not NULL,
  * then return this fixed value in *val.
  */
-int isl_basic_set_fast_dim_is_fixed(struct isl_basic_set *bset, unsigned dim,
-       isl_int *val)
+int isl_basic_set_plain_dim_is_fixed(__isl_keep isl_basic_set *bset,
+       unsigned dim, isl_int *val)
 {
-       return isl_basic_set_fast_has_fixed_var(bset,
+       return isl_basic_set_plain_has_fixed_var(bset,
                                        isl_basic_set_n_param(bset) + dim, val);
 }
 
 /* Check if dimension dim has fixed value and if so and if val is not NULL,
  * then return this fixed value in *val.
  */
-int isl_set_fast_dim_is_fixed(struct isl_set *set, unsigned dim, isl_int *val)
+int isl_set_plain_dim_is_fixed(__isl_keep isl_set *set,
+       unsigned dim, isl_int *val)
+{
+       return isl_set_plain_has_fixed_var(set, isl_set_n_param(set) + dim, val);
+}
+
+int isl_set_fast_dim_is_fixed(__isl_keep isl_set *set,
+       unsigned dim, isl_int *val)
 {
-       return isl_set_fast_has_fixed_var(set, isl_set_n_param(set) + dim, val);
+       return isl_set_plain_dim_is_fixed(set, dim, val);
 }
 
 /* Check if input variable in has fixed value and if so and if val is not NULL,
  * then return this fixed value in *val.
  */
-int isl_map_fast_input_is_fixed(struct isl_map *map, unsigned in, isl_int *val)
+int isl_map_plain_input_is_fixed(__isl_keep isl_map *map,
+       unsigned in, isl_int *val)
 {
-       return isl_map_fast_has_fixed_var(map, isl_map_n_param(map) + in, val);
+       return isl_map_plain_has_fixed_var(map, isl_map_n_param(map) + in, val);
 }
 
 /* Check if dimension dim has an (obvious) fixed lower bound and if so
  * and if val is not NULL, then return this lower bound in *val.
  */
-int isl_basic_set_fast_dim_has_fixed_lower_bound(struct isl_basic_set *bset,
-       unsigned dim, isl_int *val)
+int isl_basic_set_plain_dim_has_fixed_lower_bound(
+       __isl_keep isl_basic_set *bset, unsigned dim, isl_int *val)
 {
        int i, i_eq = -1, i_ineq = -1;
        isl_int *c;
@@ -6790,7 +6922,7 @@ int isl_basic_set_fast_dim_has_fixed_lower_bound(struct isl_basic_set *bset,
        return 1;
 }
 
-int isl_set_fast_dim_has_fixed_lower_bound(struct isl_set *set,
+int isl_set_plain_dim_has_fixed_lower_bound(__isl_keep isl_set *set,
        unsigned dim, isl_int *val)
 {
        int i;
@@ -6803,14 +6935,14 @@ int isl_set_fast_dim_has_fixed_lower_bound(struct isl_set *set,
        if (set->n == 0)
                return 0;
        if (set->n == 1)
-               return isl_basic_set_fast_dim_has_fixed_lower_bound(set->p[0],
+               return isl_basic_set_plain_dim_has_fixed_lower_bound(set->p[0],
                                                                dim, val);
        isl_int_init(v);
        isl_int_init(tmp);
-       fixed = isl_basic_set_fast_dim_has_fixed_lower_bound(set->p[0],
+       fixed = isl_basic_set_plain_dim_has_fixed_lower_bound(set->p[0],
                                                                dim, &v);
        for (i = 1; fixed == 1 && i < set->n; ++i) {
-               fixed = isl_basic_set_fast_dim_has_fixed_lower_bound(set->p[i],
+               fixed = isl_basic_set_plain_dim_has_fixed_lower_bound(set->p[i],
                                                                dim, &tmp);
                if (fixed == 1 && isl_int_ne(tmp, v))
                        fixed = 0;
@@ -6898,7 +7030,7 @@ struct isl_basic_set *isl_basic_set_normalize(struct isl_basic_set *bset)
                                                (struct isl_basic_map *)bset);
 }
 
-int isl_basic_map_fast_cmp(const __isl_keep isl_basic_map *bmap1,
+int isl_basic_map_plain_cmp(const __isl_keep isl_basic_map *bmap1,
        const __isl_keep isl_basic_map *bmap2)
 {
        int i, cmp;
@@ -6947,16 +7079,16 @@ int isl_basic_map_fast_cmp(const __isl_keep isl_basic_map *bmap1,
        return 0;
 }
 
-int isl_basic_map_fast_is_equal(__isl_keep isl_basic_map *bmap1,
+int isl_basic_map_plain_is_equal(__isl_keep isl_basic_map *bmap1,
        __isl_keep isl_basic_map *bmap2)
 {
-       return isl_basic_map_fast_cmp(bmap1, bmap2) == 0;
+       return isl_basic_map_plain_cmp(bmap1, bmap2) == 0;
 }
 
-int isl_basic_set_fast_is_equal(__isl_keep isl_basic_set *bset1,
+int isl_basic_set_plain_is_equal(__isl_keep isl_basic_set *bset1,
        __isl_keep isl_basic_set *bset2)
 {
-       return isl_basic_map_fast_is_equal((isl_basic_map *)bset1,
+       return isl_basic_map_plain_is_equal((isl_basic_map *)bset1,
                                            (isl_basic_map *)bset2);
 }
 
@@ -6965,7 +7097,7 @@ static int qsort_bmap_cmp(const void *p1, const void *p2)
        const struct isl_basic_map *bmap1 = *(const struct isl_basic_map **)p1;
        const struct isl_basic_map *bmap2 = *(const struct isl_basic_map **)p2;
 
-       return isl_basic_map_fast_cmp(bmap1, bmap2);
+       return isl_basic_map_plain_cmp(bmap1, bmap2);
 }
 
 /* We normalize in place, but if anything goes wrong we need
@@ -6994,7 +7126,7 @@ struct isl_map *isl_map_normalize(struct isl_map *map)
        if (!map)
                return NULL;
        for (i = map->n - 1; i >= 1; --i) {
-               if (!isl_basic_map_fast_is_equal(map->p[i-1], map->p[i]))
+               if (!isl_basic_map_plain_is_equal(map->p[i-1], map->p[i]))
                        continue;
                isl_basic_map_free(map->p[i-1]);
                for (j = i; j < map->n; ++j)
@@ -7013,7 +7145,7 @@ struct isl_set *isl_set_normalize(struct isl_set *set)
        return (struct isl_set *)isl_map_normalize((struct isl_map *)set);
 }
 
-int isl_map_fast_is_equal(struct isl_map *map1, struct isl_map *map2)
+int isl_map_plain_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
 {
        int i;
        int equal;
@@ -7034,7 +7166,7 @@ int isl_map_fast_is_equal(struct isl_map *map1, struct isl_map *map2)
                goto error;
        equal = map1->n == map2->n;
        for (i = 0; equal && i < map1->n; ++i) {
-               equal = isl_basic_map_fast_is_equal(map1->p[i], map2->p[i]);
+               equal = isl_basic_map_plain_is_equal(map1->p[i], map2->p[i]);
                if (equal < 0)
                        goto error;
        }
@@ -7047,12 +7179,22 @@ error:
        return -1;
 }
 
-int isl_set_fast_is_equal(struct isl_set *set1, struct isl_set *set2)
+int isl_map_fast_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+       return isl_map_plain_is_equal(map1, map2);
+}
+
+int isl_set_plain_is_equal(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
 {
-       return isl_map_fast_is_equal((struct isl_map *)set1,
+       return isl_map_plain_is_equal((struct isl_map *)set1,
                                                (struct isl_map *)set2);
 }
 
+int isl_set_fast_is_equal(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+       return isl_set_plain_is_equal(set1, set2);
+}
+
 /* Return an interval that ranges from min to max (inclusive)
  */
 struct isl_basic_set *isl_basic_set_interval(struct isl_ctx *ctx,
@@ -7170,8 +7312,8 @@ struct isl_basic_map *isl_basic_map_product(
                        bmap1->n_div + bmap2->n_div,
                        bmap1->n_eq + bmap2->n_eq,
                        bmap1->n_ineq + bmap2->n_ineq);
-       bmap = add_constraints_dim_map(bmap, bmap1, dim_map1);
-       bmap = add_constraints_dim_map(bmap, bmap2, dim_map2);
+       bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+       bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
        bmap = isl_basic_map_simplify(bmap);
        return isl_basic_map_finalize(bmap);
 error:
@@ -7231,8 +7373,8 @@ __isl_give isl_basic_map *isl_basic_map_range_product(
                        bmap1->n_div + bmap2->n_div,
                        bmap1->n_eq + bmap2->n_eq,
                        bmap1->n_ineq + bmap2->n_ineq);
-       bmap = add_constraints_dim_map(bmap, bmap1, dim_map1);
-       bmap = add_constraints_dim_map(bmap, bmap2, dim_map2);
+       bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+       bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
        bmap = isl_basic_map_simplify(bmap);
        return isl_basic_map_finalize(bmap);
 error:
@@ -7766,7 +7908,7 @@ int isl_basic_set_dims_get_sign(__isl_keep isl_basic_set *bset,
  * an equality that defines the output dimension in terms of
  * earlier dimensions.
  */
-int isl_basic_map_fast_is_single_valued(__isl_keep isl_basic_map *bmap)
+int isl_basic_map_plain_is_single_valued(__isl_keep isl_basic_map *bmap)
 {
        int i, j;
        unsigned total;
@@ -7797,7 +7939,7 @@ int isl_basic_map_fast_is_single_valued(__isl_keep isl_basic_map *bmap)
 
 /* Check if the given map is obviously single-valued.
  */
-int isl_map_fast_is_single_valued(__isl_keep isl_map *map)
+int isl_map_plain_is_single_valued(__isl_keep isl_map *map)
 {
        int sv;
 
@@ -7808,7 +7950,7 @@ int isl_map_fast_is_single_valued(__isl_keep isl_map *map)
        if (map->n >= 2)
                return 0;
 
-       return isl_basic_map_fast_is_single_valued(map->p[0]);
+       return isl_basic_map_plain_is_single_valued(map->p[0]);
 }
 
 /* Check if the given map is single-valued.
@@ -7825,7 +7967,7 @@ int isl_map_is_single_valued(__isl_keep isl_map *map)
        isl_map *id;
        int sv;
 
-       sv = isl_map_fast_is_single_valued(map);
+       sv = isl_map_plain_is_single_valued(map);
        if (sv < 0 || sv)
                return sv;
 
@@ -7843,6 +7985,32 @@ int isl_map_is_single_valued(__isl_keep isl_map *map)
        return sv;
 }
 
+int isl_map_is_injective(__isl_keep isl_map *map)
+{
+       int in;
+
+       map = isl_map_copy(map);
+       map = isl_map_reverse(map);
+       in = isl_map_is_single_valued(map);
+       isl_map_free(map);
+
+       return in;
+}
+
+/* Check if the given map is obviously injective.
+ */
+int isl_map_plain_is_injective(__isl_keep isl_map *map)
+{
+       int in;
+
+       map = isl_map_copy(map);
+       map = isl_map_reverse(map);
+       in = isl_map_plain_is_single_valued(map);
+       isl_map_free(map);
+
+       return in;
+}
+
 int isl_map_is_bijective(__isl_keep isl_map *map)
 {
        int sv;
@@ -7851,12 +8019,7 @@ int isl_map_is_bijective(__isl_keep isl_map *map)
        if (sv < 0 || !sv)
                return sv;
 
-       map = isl_map_copy(map);
-       map = isl_map_reverse(map);
-       sv = isl_map_is_single_valued(map);
-       isl_map_free(map);
-
-       return sv;
+       return isl_map_is_injective(map);
 }
 
 int isl_set_is_singleton(__isl_keep isl_set *set)
@@ -8174,53 +8337,6 @@ __isl_give isl_map *isl_set_flatten_map(__isl_take isl_set *set)
        return map;
 }
 
-/* Extend the given dim_map with mappings for the divs in bmap.
- */
-static __isl_give struct isl_dim_map *extend_dim_map(
-       __isl_keep struct isl_dim_map *dim_map,
-       __isl_keep isl_basic_map *bmap)
-{
-       int i;
-       struct isl_dim_map *res;
-       int offset;
-
-       offset = isl_basic_map_offset(bmap, isl_dim_div);
-
-       res = isl_dim_map_alloc(bmap->ctx, dim_map->len - 1 + bmap->n_div);
-       if (!res)
-               return NULL;
-
-       for (i = 0; i < dim_map->len; ++i)
-               res->pos[i] = dim_map->pos[i];
-       for (i = 0; i < bmap->n_div; ++i)
-               res->pos[dim_map->len + i] = offset + i;
-
-       return res;
-}
-
-/* Extract a dim_map from a reordering.
- * We essentially need to reverse the mapping, and add an offset
- * of 1 for the constant term.
- */
-__isl_give struct isl_dim_map *isl_dim_map_from_reordering(
-       __isl_keep isl_reordering *exp)
-{
-       int i;
-       struct isl_dim_map *dim_map;
-
-       if (!exp)
-               return NULL;
-
-       dim_map = isl_dim_map_alloc(exp->dim->ctx, isl_dim_total(exp->dim));
-       if (!dim_map)
-               return NULL;
-
-       for (i = 0; i < exp->len; ++i)
-               dim_map->pos[1 + exp->pos[i]] = 1 + i;
-
-       return dim_map;
-}
-
 /* Reorder the dimensions of "bmap" according to the given dim_map
  * and set the dimension specification to "dim".
  */
@@ -8235,7 +8351,7 @@ __isl_give isl_basic_map *isl_basic_map_realign(__isl_take isl_basic_map *bmap,
 
        res = isl_basic_map_alloc_dim(dim,
                        bmap->n_div, bmap->n_eq, bmap->n_ineq);
-       res = add_constraints_dim_map(res, bmap, dim_map);
+       res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
        res = isl_basic_map_finalize(res);
        return res;
 error:
@@ -8261,7 +8377,7 @@ __isl_give isl_map *isl_map_realign(__isl_take isl_map *map,
        for (i = 0; i < map->n; ++i) {
                struct isl_dim_map *dim_map_i;
 
-               dim_map_i = extend_dim_map(dim_map, map->p[i]);
+               dim_map_i = isl_dim_map_extend(dim_map, map->p[i]);
 
                map->p[i] = isl_basic_map_realign(map->p[i],
                                            isl_dim_copy(r->dim), dim_map_i);
@@ -8288,6 +8404,47 @@ __isl_give isl_set *isl_set_realign(__isl_take isl_set *set,
        return (isl_set *)isl_map_realign((isl_map *)set, r);
 }
 
+__isl_give isl_map *isl_map_align_params(__isl_take isl_map *map,
+       __isl_take isl_dim *model)
+{
+       isl_ctx *ctx;
+
+       if (!map || !model)
+               goto error;
+
+       ctx = isl_dim_get_ctx(model);
+       if (!isl_dim_has_named_params(model))
+               isl_die(ctx, isl_error_invalid,
+                       "model has unnamed parameters", goto error);
+       if (!isl_dim_has_named_params(map->dim))
+               isl_die(ctx, isl_error_invalid,
+                       "relation has unnamed parameters", goto error);
+       if (!isl_dim_match(map->dim, isl_dim_param, model, isl_dim_param)) {
+               isl_reordering *exp;
+
+               model = isl_dim_drop(model, isl_dim_in,
+                                       0, isl_dim_size(model, isl_dim_in));
+               model = isl_dim_drop(model, isl_dim_out,
+                                       0, isl_dim_size(model, isl_dim_out));
+               exp = isl_parameter_alignment_reordering(map->dim, model);
+               exp = isl_reordering_extend_dim(exp, isl_map_get_dim(map));
+               map = isl_map_realign(map, exp);
+       }
+
+       isl_dim_free(model);
+       return map;
+error:
+       isl_dim_free(model);
+       isl_map_free(map);
+       return NULL;
+}
+
+__isl_give isl_set *isl_set_align_params(__isl_take isl_set *set,
+       __isl_take isl_dim *model)
+{
+       return isl_map_align_params(set, model);
+}
+
 __isl_give isl_mat *isl_basic_map_equalities_matrix(
                __isl_keep isl_basic_map *bmap, enum isl_dim_type c1,
                enum isl_dim_type c2, enum isl_dim_type c3,
index 031ba62..415965f 100644 (file)
@@ -111,7 +111,11 @@ __isl_give isl_map *isl_map_reset_dim(__isl_take isl_map *map,
 
 unsigned isl_basic_map_offset(struct isl_basic_map *bmap,
                                        enum isl_dim_type type);
+unsigned isl_basic_set_offset(struct isl_basic_set *bset,
+                                       enum isl_dim_type type);
 
+int isl_basic_map_may_be_set(__isl_keep isl_basic_map *bmap);
+int isl_map_may_be_set(__isl_keep isl_map *map);
 int isl_map_compatible_domain(struct isl_map *map, struct isl_set *set);
 int isl_basic_map_compatible_domain(struct isl_basic_map *bmap,
                struct isl_basic_set *bset);
@@ -192,11 +196,11 @@ struct isl_basic_set *isl_basic_set_gauss(
        struct isl_basic_set *bset, int *progress);
 __isl_give isl_basic_set *isl_basic_set_sort_constraints(
        __isl_take isl_basic_set *bset);
-int isl_basic_map_fast_cmp(const __isl_keep isl_basic_map *bmap1,
+int isl_basic_map_plain_cmp(const __isl_keep isl_basic_map *bmap1,
        const __isl_keep isl_basic_map *bmap2);
-int isl_basic_set_fast_is_equal(__isl_keep isl_basic_set *bset1,
+int isl_basic_set_plain_is_equal(__isl_keep isl_basic_set *bset1,
        __isl_keep isl_basic_set *bset2);
-int isl_basic_map_fast_is_equal(__isl_keep isl_basic_map *bmap1,
+int isl_basic_map_plain_is_equal(__isl_keep isl_basic_map *bmap1,
        __isl_keep isl_basic_map *bmap2);
 struct isl_basic_map *isl_basic_map_normalize_constraints(
        struct isl_basic_map *bmap);
@@ -267,6 +271,10 @@ struct isl_basic_set *isl_basic_set_preimage(struct isl_basic_set *bset,
        struct isl_mat *mat);
 struct isl_set *isl_set_preimage(struct isl_set *set, struct isl_mat *mat);
 
+__isl_give isl_basic_set *isl_basic_set_transform_dims(
+       __isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned first,
+       __isl_take isl_mat *trans);
+
 isl_int *isl_set_wrap_facet(__isl_keep isl_set *set,
        isl_int *facet, isl_int *ridge);
 
@@ -287,4 +295,11 @@ int isl_basic_set_add_div_constraints_var(__isl_keep isl_basic_set *bset,
 int isl_basic_map_is_div_constraint(__isl_keep isl_basic_map *bmap,
        isl_int *constraint, unsigned div);
 
+__isl_give isl_basic_set *isl_basic_set_from_local_space(
+       __isl_take isl_local_space *ls);
+__isl_give isl_basic_map *isl_basic_map_from_local_space(
+       __isl_take isl_local_space *ls);
+__isl_give isl_basic_set *isl_basic_set_expand_divs(
+       __isl_take isl_basic_set *bset, __isl_take isl_mat *div, int *exp);
+
 #endif
index 157d6b7..984eb58 100644 (file)
@@ -813,7 +813,7 @@ static struct isl_basic_map *normalize_divs(
                return bmap;
 
        if (div_eq < bmap->n_eq) {
-               B = isl_mat_sub_alloc(bmap->ctx, bmap->eq, div_eq,
+               B = isl_mat_sub_alloc6(bmap->ctx, bmap->eq, div_eq,
                                        bmap->n_eq - div_eq, 0, 1 + total);
                C = isl_mat_variable_compression(B, &C2);
                if (!C || !C2)
@@ -834,7 +834,7 @@ static struct isl_basic_map *normalize_divs(
                        --j;
                isl_int_set(d->block.data[i], bmap->eq[i][1 + total + j]);
        }
-       B = isl_mat_sub_alloc(bmap->ctx, bmap->eq, 0, div_eq, 0, 1 + total);
+       B = isl_mat_sub_alloc6(bmap->ctx, bmap->eq, 0, div_eq, 0, 1 + total);
 
        if (C) {
                B = isl_mat_product(B, C);
@@ -1559,7 +1559,7 @@ static struct isl_basic_set *normalize_constraints_in_compressed_space(
                return NULL;
 
        total = isl_basic_set_total_dim(bset);
-       B = isl_mat_sub_alloc(bset->ctx, bset->eq, 0, bset->n_eq, 0, 1 + total);
+       B = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq, 0, 1 + total);
        C = isl_mat_variable_compression(B, NULL);
        if (!C)
                return bset;
@@ -1567,7 +1567,7 @@ static struct isl_basic_set *normalize_constraints_in_compressed_space(
                isl_mat_free(C);
                return isl_basic_set_set_to_empty(bset);
        }
-       B = isl_mat_sub_alloc(bset->ctx, bset->ineq,
+       B = isl_mat_sub_alloc6(bset->ctx, bset->ineq,
                                                0, bset->n_ineq, 0, 1 + total);
        C = isl_mat_product(B, C);
        if (!C)
@@ -1724,7 +1724,7 @@ static __isl_give isl_basic_set *uset_gist(__isl_take isl_basic_set *bset,
                goto error;
 
        bset = isl_basic_set_intersect(bset, isl_basic_set_copy(context));
-       if (isl_basic_set_fast_is_empty(bset)) {
+       if (isl_basic_set_plain_is_empty(bset)) {
                isl_basic_set_free(context);
                return bset;
        }
@@ -1732,7 +1732,7 @@ static __isl_give isl_basic_set *uset_gist(__isl_take isl_basic_set *bset,
        aff = isl_basic_set_affine_hull(isl_basic_set_copy(bset));
        if (!aff)
                goto error;
-       if (isl_basic_set_fast_is_empty(aff)) {
+       if (isl_basic_set_plain_is_empty(aff)) {
                isl_basic_set_free(aff);
                isl_basic_set_free(context);
                return bset;
@@ -1742,7 +1742,7 @@ static __isl_give isl_basic_set *uset_gist(__isl_take isl_basic_set *bset,
                return uset_gist_full(bset, context);
        }
        total = isl_basic_set_total_dim(bset);
-       eq = isl_mat_sub_alloc(bset->ctx, aff->eq, 0, aff->n_eq, 0, 1 + total);
+       eq = isl_mat_sub_alloc6(bset->ctx, aff->eq, 0, aff->n_eq, 0, 1 + total);
        eq = isl_mat_cow(eq);
        T = isl_mat_variable_compression(eq, &T2);
        if (T && T->n_col == 0) {
@@ -1824,13 +1824,13 @@ struct isl_basic_map *isl_basic_map_gist(struct isl_basic_map *bmap,
                isl_basic_map_free(context);
                return bmap;
        }
-       if (isl_basic_map_fast_is_empty(context)) {
+       if (isl_basic_map_plain_is_empty(context)) {
                struct isl_dim *dim = isl_dim_copy(bmap->dim);
                isl_basic_map_free(context);
                isl_basic_map_free(bmap);
                return isl_basic_map_universe(dim);
        }
-       if (isl_basic_map_fast_is_empty(bmap)) {
+       if (isl_basic_map_plain_is_empty(bmap)) {
                isl_basic_map_free(context);
                return bmap;
        }
@@ -1865,7 +1865,7 @@ __isl_give isl_map *isl_map_gist_basic_map(__isl_take isl_map *map,
        if (!map || !context)
                goto error;;
 
-       if (isl_basic_map_fast_is_empty(context)) {
+       if (isl_basic_map_plain_is_empty(context)) {
                struct isl_dim *dim = isl_dim_copy(map->dim);
                isl_basic_map_free(context);
                isl_map_free(map);
@@ -1885,7 +1885,7 @@ __isl_give isl_map *isl_map_gist_basic_map(__isl_take isl_map *map,
                                                isl_basic_map_copy(context));
                if (!map->p[i])
                        goto error;
-               if (isl_basic_map_fast_is_empty(map->p[i])) {
+               if (isl_basic_map_plain_is_empty(map->p[i])) {
                        isl_basic_map_free(map->p[i]);
                        if (i != map->n - 1)
                                map->p[i] = map->p[map->n - 1];
@@ -1934,8 +1934,8 @@ __isl_give isl_set *isl_set_gist(__isl_take isl_set *set,
  * one basic map in the context of the equalities of the other
  * basic map and check if we get a contradiction.
  */
-int isl_basic_map_fast_is_disjoint(struct isl_basic_map *bmap1,
-       struct isl_basic_map *bmap2)
+int isl_basic_map_plain_is_disjoint(__isl_keep isl_basic_map *bmap1,
+       __isl_keep isl_basic_map *bmap2)
 {
        struct isl_vec *v = NULL;
        int *elim = NULL;
@@ -1999,26 +1999,27 @@ error:
        return -1;
 }
 
-int isl_basic_set_fast_is_disjoint(struct isl_basic_set *bset1,
-       struct isl_basic_set *bset2)
+int isl_basic_set_plain_is_disjoint(__isl_keep isl_basic_set *bset1,
+       __isl_keep isl_basic_set *bset2)
 {
-       return isl_basic_map_fast_is_disjoint((struct isl_basic_map *)bset1,
+       return isl_basic_map_plain_is_disjoint((struct isl_basic_map *)bset1,
                                              (struct isl_basic_map *)bset2);
 }
 
-int isl_map_fast_is_disjoint(struct isl_map *map1, struct isl_map *map2)
+int isl_map_plain_is_disjoint(__isl_keep isl_map *map1,
+       __isl_keep isl_map *map2)
 {
        int i, j;
 
        if (!map1 || !map2)
                return -1;
 
-       if (isl_map_fast_is_equal(map1, map2))
+       if (isl_map_plain_is_equal(map1, map2))
                return 0;
 
        for (i = 0; i < map1->n; ++i) {
                for (j = 0; j < map2->n; ++j) {
-                       int d = isl_basic_map_fast_is_disjoint(map1->p[i],
+                       int d = isl_basic_map_plain_is_disjoint(map1->p[i],
                                                               map2->p[j]);
                        if (d != 1)
                                return d;
@@ -2027,12 +2028,18 @@ int isl_map_fast_is_disjoint(struct isl_map *map1, struct isl_map *map2)
        return 1;
 }
 
-int isl_set_fast_is_disjoint(struct isl_set *set1, struct isl_set *set2)
+int isl_set_plain_is_disjoint(__isl_keep isl_set *set1,
+       __isl_keep isl_set *set2)
 {
-       return isl_map_fast_is_disjoint((struct isl_map *)set1,
+       return isl_map_plain_is_disjoint((struct isl_map *)set1,
                                        (struct isl_map *)set2);
 }
 
+int isl_set_fast_is_disjoint(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+       return isl_set_plain_is_disjoint(set1, set2);
+}
+
 /* Check if we can combine a given div with lower bound l and upper
  * bound u with some other div and if so return that other div.
  * Otherwise return -1.
index dc20d91..1cdd68e 100644 (file)
@@ -560,7 +560,7 @@ static int basic_map_diff_is_empty(__isl_keep isl_basic_map *bmap,
        int r;
        struct isl_is_empty_diff_collector edc;
 
-       r = isl_basic_map_fast_is_empty(bmap);
+       r = isl_basic_map_plain_is_empty(bmap);
        if (r)
                return r;
 
@@ -596,7 +596,7 @@ static int map_diff_is_empty(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
 
 /* Return 1 if "bmap" contains a single element.
  */
-int isl_basic_map_fast_is_singleton(__isl_keep isl_basic_map *bmap)
+int isl_basic_map_plain_is_singleton(__isl_keep isl_basic_map *bmap)
 {
        if (!bmap)
                return -1;
@@ -609,14 +609,14 @@ int isl_basic_map_fast_is_singleton(__isl_keep isl_basic_map *bmap)
 
 /* Return 1 if "map" contains a single element.
  */
-int isl_map_fast_is_singleton(__isl_keep isl_map *map)
+int isl_map_plain_is_singleton(__isl_keep isl_map *map)
 {
        if (!map)
                return -1;
        if (map->n != 1)
                return 0;
 
-       return isl_basic_map_fast_is_singleton(map->p[0]);
+       return isl_basic_map_plain_is_singleton(map->p[0]);
 }
 
 /* Given a singleton basic map, extract the single element
@@ -717,11 +717,11 @@ int isl_map_is_subset(struct isl_map *map1, struct isl_map *map2)
        if (isl_map_is_empty(map2))
                return 0;
 
-       if (isl_map_fast_is_universe(map2))
+       if (isl_map_plain_is_universe(map2))
                return 1;
 
        map2 = isl_map_compute_divs(isl_map_copy(map2));
-       if (isl_map_fast_is_singleton(map1)) {
+       if (isl_map_plain_is_singleton(map1)) {
                is_subset = map_is_singleton_subset(map1, map2);
                isl_map_free(map2);
                return is_subset;
index 90e981f..dc64b63 100644 (file)
--- a/isl_mat.c
+++ b/isl_mat.c
 #include "isl_map_private.h"
 #include <isl_dim_private.h>
 
+isl_ctx *isl_mat_get_ctx(__isl_keep isl_mat *mat)
+{
+       return mat ? mat->ctx : NULL;
+}
+
 struct isl_mat *isl_mat_alloc(struct isl_ctx *ctx,
        unsigned n_row, unsigned n_col)
 {
@@ -107,7 +112,7 @@ error:
        return NULL;
 }
 
-struct isl_mat *isl_mat_sub_alloc(struct isl_ctx *ctx, isl_int **row,
+__isl_give isl_mat *isl_mat_sub_alloc6(isl_ctx *ctx, isl_int **row,
        unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col)
 {
        int i;
@@ -134,6 +139,15 @@ error:
        return NULL;
 }
 
+__isl_give isl_mat *isl_mat_sub_alloc(__isl_keep isl_mat *mat,
+       unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col)
+{
+       if (!mat)
+               return NULL;
+       return isl_mat_sub_alloc6(mat->ctx, mat->row, first_row, n_row,
+                                 first_col, n_col);
+}
+
 void isl_mat_sub_copy(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
        unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col)
 {
@@ -248,6 +262,25 @@ error:
        return NULL;
 }
 
+__isl_give isl_mat *isl_mat_set_element_si(__isl_take isl_mat *mat,
+       int row, int col, int v)
+{
+       mat = isl_mat_cow(mat);
+       if (!mat)
+               return NULL;
+       if (row < 0 || row >= mat->n_row)
+               isl_die(mat->ctx, isl_error_invalid, "row out of range",
+                       goto error);
+       if (col < 0 || col >= mat->n_col)
+               isl_die(mat->ctx, isl_error_invalid, "column out of range",
+                       goto error);
+       isl_int_set_si(mat->row[row][col], v);
+       return mat;
+error:
+       isl_mat_free(mat);
+       return NULL;
+}
+
 struct isl_mat *isl_mat_identity(struct isl_ctx *ctx, unsigned n_row)
 {
        int i;
@@ -985,7 +1018,7 @@ static int preimage(struct isl_ctx *ctx, isl_int **q, unsigned n,
        if (has_div)
                for (i = 0; i < n; ++i)
                        isl_int_mul(q[i][0], q[i][0], mat->row[0][0]);
-       t = isl_mat_sub_alloc(mat->ctx, q, 0, n, has_div, mat->n_row);
+       t = isl_mat_sub_alloc6(mat->ctx, q, 0, n, has_div, mat->n_row);
        t = isl_mat_product(t, mat);
        if (!t)
                return -1;
@@ -1097,7 +1130,74 @@ error:
        return NULL;
 }
 
-void isl_mat_dump(struct isl_mat *mat, FILE *out, int indent)
+/* Replace the variables x starting at pos in the rows q
+ * by x' with x = M x' with M the matrix mat.
+ * That is, replace the corresponding coefficients c by c M.
+ */
+static int transform(isl_ctx *ctx, isl_int **q, unsigned n,
+       unsigned pos, __isl_take isl_mat *mat)
+{
+       int i;
+       isl_mat *t;
+
+       t = isl_mat_sub_alloc6(ctx, q, 0, n, pos, mat->n_row);
+       t = isl_mat_product(t, mat);
+       if (!t)
+               return -1;
+       for (i = 0; i < n; ++i)
+               isl_seq_swp_or_cpy(q[i] + pos, t->row[i], t->n_col);
+       isl_mat_free(t);
+       return 0;
+}
+
+/* Replace the variables x of type "type" starting at "first" in "bset"
+ * by x' with x = M x' with M the matrix trans.
+ * That is, replace the corresponding coefficients c by c M.
+ *
+ * The transformation matrix should be a square matrix.
+ */
+__isl_give isl_basic_set *isl_basic_set_transform_dims(
+       __isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned first,
+       __isl_take isl_mat *trans)
+{
+       isl_ctx *ctx;
+       unsigned pos;
+
+       bset = isl_basic_set_cow(bset);
+       if (!bset || !trans)
+               goto error;
+
+       ctx = isl_basic_set_get_ctx(bset);
+       if (trans->n_row != trans->n_col)
+               isl_die(trans->ctx, isl_error_invalid,
+                       "expecting square transformation matrix", goto error);
+       if (first + trans->n_row > isl_basic_set_dim(bset, type))
+               isl_die(trans->ctx, isl_error_invalid,
+                       "oversized transformation matrix", goto error);
+
+       pos = isl_basic_set_offset(bset, type) + first;
+
+       if (transform(ctx, bset->eq, bset->n_eq, pos, isl_mat_copy(trans)) < 0)
+               goto error;
+       if (transform(ctx, bset->ineq, bset->n_ineq, pos,
+                     isl_mat_copy(trans)) < 0)
+               goto error;
+       if (transform(ctx, bset->div, bset->n_div, 1 + pos,
+                     isl_mat_copy(trans)) < 0)
+               goto error;
+
+       ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED);
+       ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED_DIVS);
+
+       isl_mat_free(trans);
+       return bset;
+error:
+       isl_mat_free(trans);
+       isl_basic_set_free(bset);
+       return NULL;
+}
+
+void isl_mat_print_internal(__isl_keep isl_mat *mat, FILE *out, int indent)
 {
        int i, j;
 
@@ -1126,6 +1226,11 @@ void isl_mat_dump(struct isl_mat *mat, FILE *out, int indent)
        }
 }
 
+void isl_mat_dump(__isl_keep isl_mat *mat)
+{
+       isl_mat_print_internal(mat, stderr, 0);
+}
+
 struct isl_mat *isl_mat_drop_cols(struct isl_mat *mat, unsigned col, unsigned n)
 {
        int r;
@@ -1241,6 +1346,29 @@ __isl_give isl_mat *isl_mat_add_rows(__isl_take isl_mat *mat, unsigned n)
        return isl_mat_insert_rows(mat, mat->n_row, n);
 }
 
+__isl_give isl_mat *isl_mat_insert_zero_rows(__isl_take isl_mat *mat,
+       unsigned row, unsigned n)
+{
+       int i;
+
+       mat = isl_mat_insert_rows(mat, row, n);
+       if (!mat)
+               return NULL;
+       
+       for (i = 0; i < n; ++i)
+               isl_seq_clr(mat->row[row + i], mat->n_col);
+
+       return mat;
+}
+
+__isl_give isl_mat *isl_mat_add_zero_rows(__isl_take isl_mat *mat, unsigned n)
+{
+       if (!mat)
+               return NULL;
+
+       return isl_mat_insert_zero_rows(mat, mat->n_row, n);
+}
+
 void isl_mat_col_submul(struct isl_mat *mat,
                        int dst_col, isl_int f, int src_col)
 {
@@ -1464,3 +1592,19 @@ __isl_give isl_mat *isl_mat_normalize(__isl_take isl_mat *mat)
 
        return mat;
 }
+
+/* Number of initial non-zero columns.
+ */
+int isl_mat_initial_non_zero_cols(__isl_keep isl_mat *mat)
+{
+       int i;
+
+       if (!mat)
+               return -1;
+
+       for (i = 0; i < mat->n_col; ++i)
+               if (row_first_non_zero(mat->row, mat->n_row, i) < 0)
+                       break;
+
+       return i;
+}
index de2cc20..5ba4990 100644 (file)
@@ -18,3 +18,12 @@ struct isl_mat {
 
        struct isl_blk block;
 };
+
+__isl_give isl_mat *isl_mat_sub_alloc(__isl_keep isl_mat *mat,
+       unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col);
+__isl_give isl_mat *isl_mat_sub_alloc6(isl_ctx *ctx, isl_int **row,
+       unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col);
+void isl_mat_sub_copy(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
+       unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col);
+void isl_mat_sub_neg(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
+       unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col);
index 8a526e7..ed372ef 100644 (file)
@@ -173,8 +173,8 @@ void isl_morph_dump(__isl_take isl_morph *morph, FILE *out)
 
        isl_basic_set_print(morph->dom, out, 0, "", "", ISL_FORMAT_ISL);
        isl_basic_set_print(morph->ran, out, 0, "", "", ISL_FORMAT_ISL);
-       isl_mat_dump(morph->map, out, 4);
-       isl_mat_dump(morph->inv, out, 4);
+       isl_mat_print_internal(morph->map, out, 4);
+       isl_mat_print_internal(morph->inv, out, 4);
 }
 
 __isl_give isl_morph *isl_morph_identity(__isl_keep isl_basic_set *bset)
@@ -335,7 +335,7 @@ __isl_give isl_morph *isl_basic_set_variable_compression(
        if (!bset)
                return NULL;
 
-       if (isl_basic_set_fast_is_empty(bset))
+       if (isl_basic_set_plain_is_empty(bset))
                return isl_morph_empty(bset);
 
        isl_assert(bset->ctx, bset->n_div == 0, return NULL);
@@ -354,7 +354,7 @@ __isl_give isl_morph *isl_basic_set_variable_compression(
        if (n_eq == 0)
                return isl_morph_identity(bset);
 
-       H = isl_mat_sub_alloc(bset->ctx, bset->eq, f_eq, n_eq, otype, ntype);
+       H = isl_mat_sub_alloc6(bset->ctx, bset->eq, f_eq, n_eq, otype, ntype);
        H = isl_mat_left_hermite(H, 0, &U, &Q);
        if (!H || !U || !Q)
                goto error;
@@ -367,7 +367,7 @@ __isl_give isl_morph *isl_basic_set_variable_compression(
        isl_int_set_si(C->row[0][0], 1);
        isl_seq_clr(C->row[0] + 1, otype - 1);
        isl_mat_sub_neg(C->ctx, C->row + 1, bset->eq + f_eq, n_eq, 0, 0, otype);
-       H1 = isl_mat_sub_alloc(H->ctx, H->row, 0, H->n_row, 0, H->n_row);
+       H1 = isl_mat_sub_alloc(H, 0, H->n_row, 0, H->n_row);
        H1 = isl_mat_lin_to_aff(H1);
        C = isl_mat_inverse_product(H1, C);
        if (!C)
@@ -397,9 +397,9 @@ __isl_give isl_morph *isl_basic_set_variable_compression(
                C = isl_mat_normalize(C);
        }
 
-       U1 = isl_mat_sub_alloc(U->ctx, U->row, 0, U->n_row, 0, n_eq);
+       U1 = isl_mat_sub_alloc(U, 0, U->n_row, 0, n_eq);
        U1 = isl_mat_lin_to_aff(U1);
-       U2 = isl_mat_sub_alloc(U->ctx, U->row, 0, U->n_row, n_eq, U->n_row - n_eq);
+       U2 = isl_mat_sub_alloc(U, 0, U->n_row, n_eq, U->n_row - n_eq);
        U2 = isl_mat_lin_to_aff(U2);
        isl_mat_free(U);
 
@@ -452,7 +452,7 @@ __isl_give isl_morph *isl_basic_set_parameter_compression(
        if (!bset)
                return NULL;
 
-       if (isl_basic_set_fast_is_empty(bset))
+       if (isl_basic_set_plain_is_empty(bset))
                return isl_morph_empty(bset);
        if (bset->n_eq == 0)
                return isl_morph_identity(bset);
@@ -466,8 +466,8 @@ __isl_give isl_morph *isl_basic_set_parameter_compression(
        isl_assert(bset->ctx, n_eq <= nvar, return NULL);
 
        d = isl_vec_alloc(bset->ctx, n_eq);
-       B = isl_mat_sub_alloc(bset->ctx, bset->eq, 0, n_eq, 0, 1 + nparam);
-       H = isl_mat_sub_alloc(bset->ctx, bset->eq, 0, n_eq, 1 + nparam, nvar);
+       B = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, n_eq, 0, 1 + nparam);
+       H = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, n_eq, 1 + nparam, nvar);
        H = isl_mat_left_hermite(H, 0, NULL, NULL);
        H = isl_mat_drop_cols(H, n_eq, nvar - n_eq);
        H = isl_mat_lin_to_aff(H);
@@ -583,7 +583,7 @@ __isl_give isl_basic_set *isl_morph_basic_set(__isl_take isl_morph *morph,
                if (isl_basic_set_alloc_div(res) < 0)
                        goto error;
 
-       mat = isl_mat_sub_alloc(bset->ctx, bset->eq, 0, bset->n_eq,
+       mat = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq,
                                        0, morph->inv->n_row);
        mat = isl_mat_product(mat, isl_mat_copy(morph->inv));
        if (!mat)
@@ -598,7 +598,7 @@ __isl_give isl_basic_set *isl_morph_basic_set(__isl_take isl_morph *morph,
        }
        isl_mat_free(mat);
 
-       mat = isl_mat_sub_alloc(bset->ctx, bset->ineq, 0, bset->n_ineq,
+       mat = isl_mat_sub_alloc6(bset->ctx, bset->ineq, 0, bset->n_ineq,
                                        0, morph->inv->n_row);
        mat = isl_mat_product(mat, isl_mat_copy(morph->inv));
        if (!mat)
@@ -614,7 +614,7 @@ __isl_give isl_basic_set *isl_morph_basic_set(__isl_take isl_morph *morph,
        }
        isl_mat_free(mat);
 
-       mat = isl_mat_sub_alloc(bset->ctx, bset->div, 0, bset->n_div,
+       mat = isl_mat_sub_alloc6(bset->ctx, bset->div, 0, bset->n_div,
                                        1, morph->inv->n_row);
        mat = isl_mat_product(mat, isl_mat_copy(morph->inv));
        if (!mat)
index 70ebd23..d382af7 100644 (file)
@@ -115,6 +115,8 @@ ISL_ARG_BOOL(struct isl_options, pip_symmetry, 0, "pip-symmetry", 1,
        "detect simple symmetries in PIP input")
 ISL_ARG_CHOICE(struct isl_options, convex, 0, "convex-hull", \
        convex, ISL_CONVEX_HULL_WRAP, "convex hull algorithm to use")
+ISL_ARG_BOOL(struct isl_options, schedule_parametric, 0,
+       "schedule-parametric", 1, "construct possibly parametric schedules")
 ISL_ARG_VERSION(print_version)
 ISL_ARG_END
 };
index ffdb3e2..fa892db 100644 (file)
@@ -21,6 +21,9 @@
 #include <isl_dim_private.h>
 #include <isl_mat_private.h>
 #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 " };
@@ -474,7 +477,12 @@ static __isl_give isl_printer *print_constraints(__isl_keep isl_basic_map *bmap,
 
        for (i = bmap->n_eq - 1; i >= 0; --i) {
                int l = isl_seq_last_non_zero(bmap->eq[i], 1 + total);
-               isl_assert(bmap->ctx, l >= 0, goto error);
+               if (l < 0) {
+                       if (i != bmap->n_eq - 1)
+                               p = isl_printer_print_str(p, s_and[latex]);
+                       p = isl_printer_print_str(p, "0 = 0");
+                       continue;
+               }
                if (isl_int_is_neg(bmap->eq[i][l]))
                        isl_seq_cpy(c->el, bmap->eq[i], 1 + total);
                else
@@ -660,7 +668,7 @@ static __isl_give isl_printer *print_disjuncts(__isl_keep isl_map *map,
 {
        int i;
 
-       if (isl_map_fast_is_universe(map))
+       if (isl_map_plain_is_universe(map))
                return p;
 
        p = isl_printer_print_str(p, s_such_that[latex]);
@@ -737,7 +745,7 @@ static int aff_split_cmp(const void *p1, const void *p2)
        s1 = (const struct isl_aff_split *) p1;
        s2 = (const struct isl_aff_split *) p2;
 
-       return isl_basic_map_fast_cmp(s1->aff, s2->aff);
+       return isl_basic_map_plain_cmp(s1->aff, s2->aff);
 }
 
 static __isl_give isl_basic_map *drop_aff(__isl_take isl_basic_map *bmap,
@@ -795,7 +803,7 @@ static __isl_give struct isl_aff_split *split_aff(__isl_keep isl_map *map)
 
        n = map->n;
        for (i = n - 1; i >= 1; --i) {
-               if (!isl_basic_map_fast_is_equal(split[i - 1].aff,
+               if (!isl_basic_map_plain_is_equal(split[i - 1].aff,
                                                 split[i].aff))
                        continue;
                isl_basic_map_free(split[i].aff);
@@ -1473,7 +1481,7 @@ error:
        return NULL;
 }
 
-__isl_give isl_printer *isl_printer_print_qpolynomial(__isl_take isl_printer *p,
+static __isl_give isl_printer *print_qpolynomial(__isl_take isl_printer *p,
        __isl_keep isl_qpolynomial *qp)
 {
        if (!p || !qp)
@@ -1485,6 +1493,75 @@ error:
        return NULL;
 }
 
+static __isl_give isl_printer *print_qpolynomial_isl(__isl_take isl_printer *p,
+       __isl_keep isl_qpolynomial *qp)
+{
+       if (!p || !qp)
+               goto error;
+
+       if (isl_dim_size(qp->dim, isl_dim_param) > 0) {
+               p = print_tuple(qp->dim, p, isl_dim_param, 0, 0, NULL);
+               p = isl_printer_print_str(p, " -> ");
+       }
+       p = isl_printer_print_str(p, "{ ");
+       if (isl_dim_size(qp->dim, isl_dim_set) > 0 ||
+           isl_dim_is_named_or_nested(qp->dim, isl_dim_set)) {
+               p = print_dim(qp->dim, p, 1, 0, 0, NULL);
+               p = isl_printer_print_str(p, " -> ");
+       }
+       p = print_qpolynomial(p, qp);
+       p = isl_printer_print_str(p, " }");
+       return p;
+error:
+       isl_printer_free(p);
+       return NULL;
+}
+
+static __isl_give isl_printer *print_qpolynomial_c(__isl_take isl_printer *p,
+       __isl_keep isl_dim *dim, __isl_keep isl_qpolynomial *qp)
+{
+       isl_int den;
+
+       isl_int_init(den);
+       isl_qpolynomial_get_den(qp, &den);
+       if (!isl_int_is_one(den)) {
+               isl_qpolynomial *f;
+               p = isl_printer_print_str(p, "(");
+               qp = isl_qpolynomial_copy(qp);
+               f = isl_qpolynomial_rat_cst(isl_dim_copy(qp->dim),
+                                               den, qp->dim->ctx->one);
+               qp = isl_qpolynomial_mul(qp, f);
+       }
+       if (qp)
+               p = upoly_print(qp->upoly, dim, qp->div, p, 0);
+       if (!isl_int_is_one(den)) {
+               p = isl_printer_print_str(p, ")/");
+               p = isl_printer_print_isl_int(p, den);
+               isl_qpolynomial_free(qp);
+       }
+       isl_int_clear(den);
+       return p;
+}
+
+__isl_give isl_printer *isl_printer_print_qpolynomial(
+       __isl_take isl_printer *p, __isl_keep isl_qpolynomial *qp)
+{
+       if (!p || !qp)
+               goto error;
+
+       if (p->output_format == ISL_FORMAT_ISL)
+               return print_qpolynomial_isl(p, qp);
+       else if (p->output_format == ISL_FORMAT_C)
+               return print_qpolynomial_c(p, qp->dim, qp);
+       else
+               isl_die(qp->dim->ctx, isl_error_unsupported,
+                       "output format not supported for isl_qpolynomials",
+                       goto error);
+error:
+       isl_printer_free(p);
+       return NULL;
+}
+
 void isl_qpolynomial_print(__isl_keep isl_qpolynomial *qp, FILE *out,
        unsigned output_format)
 {
@@ -1512,7 +1589,7 @@ static __isl_give isl_printer *qpolynomial_fold_print(
        for (i = 0; i < fold->n; ++i) {
                if (i)
                        p = isl_printer_print_str(p, ", ");
-               p = isl_printer_print_qpolynomial(p, fold->qp[i]);
+               p = print_qpolynomial(p, fold->qp[i]);
        }
        p = isl_printer_print_str(p, ")");
        return p;
@@ -1547,7 +1624,7 @@ static __isl_give isl_printer *isl_pwqp_print_isl_body(
                        p = print_dim(pwqp->p[i].set->dim, p, 1, 0, 0, NULL);
                        p = isl_printer_print_str(p, " -> ");
                }
-               p = isl_printer_print_qpolynomial(p, pwqp->p[i].qp);
+               p = print_qpolynomial(p, pwqp->p[i].qp);
                p = print_disjuncts((isl_map *)pwqp->p[i].set, p, 1, 0);
        }
 
@@ -1784,38 +1861,12 @@ static __isl_give isl_printer *print_set_c(__isl_take isl_printer *p,
        return p;
 }
 
-static __isl_give isl_printer *print_qpolynomial_c(__isl_take isl_printer *p,
-       __isl_keep isl_dim *dim, __isl_keep isl_qpolynomial *qp)
-{
-       isl_int den;
-
-       isl_int_init(den);
-       isl_qpolynomial_get_den(qp, &den);
-       if (!isl_int_is_one(den)) {
-               isl_qpolynomial *f;
-               p = isl_printer_print_str(p, "(");
-               qp = isl_qpolynomial_copy(qp);
-               f = isl_qpolynomial_rat_cst(isl_dim_copy(qp->dim),
-                                               den, qp->dim->ctx->one);
-               qp = isl_qpolynomial_mul(qp, f);
-       }
-       if (qp)
-               p = upoly_print(qp->upoly, dim, qp->div, p, 0);
-       if (!isl_int_is_one(den)) {
-               p = isl_printer_print_str(p, ")/");
-               p = isl_printer_print_isl_int(p, den);
-               isl_qpolynomial_free(qp);
-       }
-       isl_int_clear(den);
-       return p;
-}
-
 static __isl_give isl_printer *print_pw_qpolynomial_c(
        __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp)
 {
        int i;
 
-       if (pwqp->n == 1 && isl_set_fast_is_universe(pwqp->p[0].set))
+       if (pwqp->n == 1 && isl_set_plain_is_universe(pwqp->p[0].set))
                return print_qpolynomial_c(p, pwqp->dim, pwqp->p[0].qp);
 
        for (i = 0; i < pwqp->n; ++i) {
@@ -1939,7 +1990,7 @@ static __isl_give isl_printer *print_pw_qpolynomial_fold_c(
 {
        int i;
 
-       if (pwf->n == 1 && isl_set_fast_is_universe(pwf->p[0].set))
+       if (pwf->n == 1 && isl_set_plain_is_universe(pwf->p[0].set))
                return print_qpolynomial_fold_c(p, pwf->dim, pwf->p[0].fold);
 
        for (i = 0; i < pwf->n; ++i) {
@@ -2036,3 +2087,137 @@ error:
        isl_printer_free(p);
        return NULL;
 }
+
+__isl_give isl_printer *isl_printer_print_constraint(__isl_take isl_printer *p,
+       __isl_keep isl_constraint *c)
+{
+       isl_basic_map *bmap;
+
+       if (!p || !c)
+               goto error;
+
+       bmap = isl_basic_map_from_constraint(isl_constraint_copy(c));
+       p = isl_printer_print_basic_map(p, bmap);
+       isl_basic_map_free(bmap);
+       return p;
+error:
+       isl_printer_free(p);
+       return NULL;
+}
+
+void isl_constraint_dump(__isl_keep isl_constraint *c)
+{
+       isl_printer *printer;
+
+       if (!c)
+               return;
+
+       printer = isl_printer_to_file(isl_constraint_get_ctx(c), stderr);
+       printer = isl_printer_print_constraint(printer, c);
+       printer = isl_printer_end_line(printer);
+
+       isl_printer_free(printer);
+}
+
+__isl_give isl_printer *isl_printer_print_local_space(__isl_take isl_printer *p,
+       __isl_keep isl_local_space *ls)
+{
+       unsigned total;
+       unsigned n_div;
+
+       if (!ls)
+               goto error;
+
+       total = isl_local_space_dim(ls, isl_dim_all);
+       if (isl_local_space_dim(ls, isl_dim_param) > 0) {
+               p = print_tuple(ls->dim, p, isl_dim_param, 0, 0, NULL);
+               p = isl_printer_print_str(p, " -> ");
+       }
+       p = isl_printer_print_str(p, "{ ");
+       p = print_tuple(ls->dim, p, isl_dim_in, 0, 0, NULL);
+       p = isl_printer_print_str(p, " -> ");
+       p = print_tuple(ls->dim, p, isl_dim_out, 0, 0, NULL);
+       n_div = isl_local_space_dim(ls, isl_dim_div);
+       if (n_div > 0) {
+               int i;
+               p = isl_printer_print_str(p, " : ");
+               p = isl_printer_print_str(p, s_open_exists[0]);
+               for (i = 0; i < n_div; ++i) {
+                       if (i)
+                               p = isl_printer_print_str(p, ", ");
+                       p = print_name(ls->dim, p, isl_dim_div, i, 0, 0);
+                       if (isl_int_is_zero(ls->div->row[i][0]))
+                               continue;
+                       p = isl_printer_print_str(p, " = [(");
+                       p = print_affine_of_len(ls->dim, ls->div, p,
+                                           ls->div->row[i] + 1, 1 + total, 0);
+                       p = isl_printer_print_str(p, ")/");
+                       p = isl_printer_print_isl_int(p, ls->div->row[i][0]);
+                       p = isl_printer_print_str(p, "]");
+               }
+       }
+       p = isl_printer_print_str(p, " }");
+       return p;
+error:
+       isl_printer_free(p);
+       return NULL;
+}
+
+void isl_local_space_dump(__isl_keep isl_local_space *ls)
+{
+       isl_printer *printer;
+
+       if (!ls)
+               return;
+
+       printer = isl_printer_to_file(isl_local_space_get_ctx(ls), stderr);
+       printer = isl_printer_print_local_space(printer, ls);
+       printer = isl_printer_end_line(printer);
+
+       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);
+}
index d8beffc..046b63a 100644 (file)
 #include <isl_polynomial_private.h>
 #include <isl_point_private.h>
 #include <isl_dim_private.h>
+#include <isl_div_private.h>
 #include <isl_mat_private.h>
 #include <isl_range.h>
+#include <isl_local_space_private.h>
+#include <isl_aff_private.h>
 
 static unsigned pos(__isl_keep isl_dim *dim, enum isl_dim_type type)
 {
@@ -1115,19 +1118,6 @@ static int compatible_divs(__isl_keep isl_mat *div1, __isl_keep isl_mat *div2)
        return equal;
 }
 
-static void expand_row(__isl_keep isl_mat *dst, int d,
-       __isl_keep isl_mat *src, int s, int *exp)
-{
-       int i;
-       unsigned c = src->n_col - src->n_row;
-
-       isl_seq_cpy(dst->row[d], src->row[s], c);
-       isl_seq_clr(dst->row[d] + c, dst->n_col - c);
-
-       for (i = 0; i < s; ++i)
-               isl_int_set(dst->row[d][c + exp[i]], src->row[s][c + i]);
-}
-
 static int cmp_row(__isl_keep isl_mat *div, int i, int j)
 {
        int li, lj;
@@ -1241,50 +1231,6 @@ error:
        return NULL;
 }
 
-static __isl_give isl_mat *merge_divs(__isl_keep isl_mat *div1,
-       __isl_keep isl_mat *div2, int *exp1, int *exp2)
-{
-       int i, j, k;
-       isl_mat *div = NULL;
-       unsigned d = div1->n_col - div1->n_row;
-
-       div = isl_mat_alloc(div1->ctx, 1 + div1->n_row + div2->n_row,
-                               d + div1->n_row + div2->n_row);
-       if (!div)
-               return NULL;
-
-       for (i = 0, j = 0, k = 0; i < div1->n_row && j < div2->n_row; ++k) {
-               int cmp;
-
-               expand_row(div, k, div1, i, exp1);
-               expand_row(div, k + 1, div2, j, exp2);
-
-               cmp = cmp_row(div, k, k + 1);
-               if (cmp == 0) {
-                       exp1[i++] = k;
-                       exp2[j++] = k;
-               } else if (cmp < 0) {
-                       exp1[i++] = k;
-               } else {
-                       exp2[j++] = k;
-                       isl_seq_cpy(div->row[k], div->row[k + 1], div->n_col);
-               }
-       }
-       for (; i < div1->n_row; ++i, ++k) {
-               expand_row(div, k, div1, i, exp1);
-               exp1[i] = k;
-       }
-       for (; j < div2->n_row; ++j, ++k) {
-               expand_row(div, k, div2, j, exp2);
-               exp2[j] = k;
-       }
-
-       div->n_row = k;
-       div->n_col = d + k;
-
-       return div;
-}
-
 static __isl_give struct isl_upoly *expand(__isl_take struct isl_upoly *up,
        int *exp, int first)
 {
@@ -1345,7 +1291,7 @@ static __isl_give isl_qpolynomial *with_merged_divs(
        if (!exp1 || !exp2)
                goto error;
 
-       div = merge_divs(qp1->div, qp2->div, exp1, exp2);
+       div = isl_merge_divs(qp1->div, qp2->div, exp1, exp2);
        if (!div)
                goto error;
 
@@ -2048,7 +1994,7 @@ static void invert_div(__isl_keep isl_qpolynomial *qp, int div,
  *
  * After the reduction, some divs may have become redundant or identical,
  * so we call substitute_non_divs and sort_divs.  If these functions
- * eliminate divs of merge * two or more divs into one, the coefficients
+ * eliminate divs or merge two or more divs into one, the coefficients
  * of the enclosing divs may have to be reduced again, so we call
  * ourselves recursively if the number of divs decreases.
  */
@@ -2226,7 +2172,7 @@ int isl_qpolynomial_involves_dims(__isl_keep isl_qpolynomial *qp,
        isl_assert(qp->dim->ctx, type == isl_dim_param ||
                                 type == isl_dim_set, return -1);
 
-       active = isl_calloc_array(set->ctx, int, isl_dim_total(qp->dim));
+       active = isl_calloc_array(qp->dim->ctx, int, isl_dim_total(qp->dim));
        if (set_active(qp, active) < 0)
                goto error;
 
@@ -2246,6 +2192,88 @@ error:
        return -1;
 }
 
+/* Remove divs that do not appear in the quasi-polynomial, nor in any
+ * of the divs that do appear in the quasi-polynomial.
+ */
+static __isl_give isl_qpolynomial *remove_redundant_divs(
+       __isl_take isl_qpolynomial *qp)
+{
+       int i, j;
+       int d;
+       int len;
+       int skip;
+       int *active = NULL;
+       int *reordering = NULL;
+       int redundant = 0;
+       int n_div;
+
+       if (!qp)
+               return NULL;
+       if (qp->div->n_row == 0)
+               return qp;
+
+       d = isl_dim_total(qp->dim);
+       len = qp->div->n_col - 2;
+       active = isl_calloc_array(qp->ctx, int, len);
+       if (!active)
+               goto error;
+
+       if (up_set_active(qp->upoly, active, len) < 0)
+               goto error;
+
+       for (i = qp->div->n_row - 1; i >= 0; --i) {
+               if (!active[d + i]) {
+                       redundant = 1;
+                       continue;
+               }
+               for (j = 0; j < i; ++j) {
+                       if (isl_int_is_zero(qp->div->row[i][2 + d + j]))
+                               continue;
+                       active[d + j] = 1;
+                       break;
+               }
+       }
+
+       if (!redundant) {
+               free(active);
+               return qp;
+       }
+
+       reordering = isl_alloc_array(qp->div->ctx, int, len);
+       if (!reordering)
+               goto error;
+
+       for (i = 0; i < d; ++i)
+               reordering[i] = i;
+
+       skip = 0;
+       n_div = qp->div->n_row;
+       for (i = 0; i < n_div; ++i) {
+               if (!active[d + i]) {
+                       qp->div = isl_mat_drop_rows(qp->div, i - skip, 1);
+                       qp->div = isl_mat_drop_cols(qp->div,
+                                                   2 + d + i - skip, 1);
+                       skip++;
+               }
+               reordering[d + i] = d + i - skip;
+       }
+
+       qp->upoly = reorder(qp->upoly, reordering);
+
+       if (!qp->upoly || !qp->div)
+               goto error;
+
+       free(active);
+       free(reordering);
+
+       return qp;
+error:
+       free(active);
+       free(reordering);
+       isl_qpolynomial_free(qp);
+       return NULL;
+}
+
 __isl_give struct isl_upoly *isl_upoly_drop(__isl_take struct isl_upoly *up,
        unsigned first, unsigned n)
 {
@@ -2485,7 +2513,7 @@ int isl_pw_qpolynomial_is_one(__isl_keep isl_pw_qpolynomial *pwqp)
        if (pwqp->n != -1)
                return 0;
 
-       if (!isl_set_fast_is_universe(pwqp->p[0].set))
+       if (!isl_set_plain_is_universe(pwqp->p[0].set))
                return 0;
 
        return isl_qpolynomial_is_one(pwqp->p[0].qp);
@@ -2534,7 +2562,7 @@ __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_mul(
                        struct isl_qpolynomial *prod;
                        common = isl_set_intersect(isl_set_copy(pwqp1->p[i].set),
                                                isl_set_copy(pwqp2->p[j].set));
-                       if (isl_set_fast_is_empty(common)) {
+                       if (isl_set_plain_is_empty(common)) {
                                isl_set_free(common);
                                continue;
                        }
@@ -2925,6 +2953,38 @@ __isl_give isl_qpolynomial *isl_qpolynomial_from_affine(__isl_take isl_dim *dim,
        return isl_qpolynomial_alloc(dim, 0, up);
 }
 
+__isl_give isl_qpolynomial *isl_qpolynomial_from_aff(__isl_take isl_aff *aff)
+{
+       isl_ctx *ctx;
+       struct isl_upoly *up;
+       isl_qpolynomial *qp;
+
+       if (!aff)
+               return NULL;
+
+       ctx = isl_aff_get_ctx(aff);
+       up = isl_upoly_from_affine(ctx, aff->v->el + 1, aff->v->el[0],
+                                   aff->v->size - 1);
+
+       qp = isl_qpolynomial_alloc(isl_aff_get_dim(aff),
+                                   aff->ls->div->n_row, up);
+       if (!qp)
+               goto error;
+
+       isl_mat_free(qp->div);
+       qp->div = isl_mat_copy(aff->ls->div);
+       if (!qp->div)
+               goto error;
+
+       isl_aff_free(aff);
+       qp = reduce_divs(qp);
+       qp = remove_redundant_divs(qp);
+       return qp;
+error:
+       isl_aff_free(aff);
+       return NULL;
+}
+
 __isl_give isl_qpolynomial *isl_qpolynomial_from_constraint(
        __isl_take isl_constraint *c, enum isl_dim_type type, unsigned pos)
 {
@@ -3890,6 +3950,33 @@ error:
        return NULL;
 }
 
+__isl_give isl_qpolynomial *isl_qpolynomial_align_params(
+       __isl_take isl_qpolynomial *qp, __isl_take isl_dim *model)
+{
+       if (!qp || !model)
+               goto error;
+
+       if (!isl_dim_match(qp->dim, isl_dim_param, model, isl_dim_param)) {
+               isl_reordering *exp;
+
+               model = isl_dim_drop(model, isl_dim_in,
+                                       0, isl_dim_size(model, isl_dim_in));
+               model = isl_dim_drop(model, isl_dim_out,
+                                       0, isl_dim_size(model, isl_dim_out));
+               exp = isl_parameter_alignment_reordering(qp->dim, model);
+               exp = isl_reordering_extend_dim(exp,
+                                               isl_qpolynomial_get_dim(qp));
+               qp = isl_qpolynomial_realign(qp, exp);
+       }
+
+       isl_dim_free(model);
+       return qp;
+error:
+       isl_dim_free(model);
+       isl_qpolynomial_free(qp);
+       return NULL;
+}
+
 struct isl_split_periods_data {
        int max_periods;
        isl_pw_qpolynomial *res;
@@ -4222,7 +4309,7 @@ __isl_give isl_pw_qpolynomial *isl_basic_set_multiplicative_call(
        if (!bset)
                return NULL;
 
-       if (isl_basic_set_fast_is_empty(bset))
+       if (isl_basic_set_plain_is_empty(bset))
                return constant_on_domain(bset, 0);
 
        orig_nvar = isl_basic_set_dim(bset, isl_dim_set);
index 317519f..74f7144 100644 (file)
@@ -202,8 +202,6 @@ __isl_give isl_qpolynomial *isl_qpolynomial_substitute_equalities(
        __isl_take isl_qpolynomial *qp, __isl_take isl_basic_set *eq);
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute_equalities(
        __isl_take isl_qpolynomial_fold *fold, __isl_take isl_basic_set *eq);
-__isl_give isl_qpolynomial *isl_qpolynomial_gist(
-       __isl_take isl_qpolynomial *qp, __isl_take isl_set *context);
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist(
        __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context);
 
index da4b53e..2e9ca0c 100644 (file)
@@ -51,7 +51,7 @@ __isl_give PW *FN(PW,add_piece)(__isl_take PW *pw,
        if (!pw || !set || !el)
                goto error;
 
-       if (isl_set_fast_is_empty(set) || FN(EL,IS_ZERO)(el)) {
+       if (isl_set_plain_is_empty(set) || FN(EL,IS_ZERO)(el)) {
                isl_set_free(set);
                FN(EL,free)(el);
                return pw;
@@ -215,7 +215,7 @@ __isl_give PW *FN(PW,add)(__isl_take PW *pw1, __isl_take PW *pw2)
                                        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_fast_is_empty(common)) {
+                       if (isl_set_plain_is_empty(common)) {
                                isl_set_free(common);
                                continue;
                        }
@@ -371,7 +371,7 @@ __isl_give PW *FN(PW,intersect_domain)(__isl_take PW *pw, __isl_take isl_set *se
                aff = isl_set_affine_hull(isl_set_copy(pw->p[i].set));
                pw->p[i].FIELD = FN(EL,substitute_equalities)(pw->p[i].FIELD,
                                                                aff);
-               if (isl_set_fast_is_empty(pw->p[i].set)) {
+               if (isl_set_plain_is_empty(pw->p[i].set)) {
                        isl_set_free(pw->p[i].set);
                        FN(EL,free)(pw->p[i].FIELD);
                        if (i != pw->n - 1)
@@ -419,7 +419,7 @@ __isl_give PW *FN(PW,gist)(__isl_take PW *pw, __isl_take isl_set *context)
                                                isl_basic_set_copy(hull));
                if (!pw->p[i].set)
                        goto error;
-               if (isl_set_fast_is_empty(pw->p[i].set)) {
+               if (isl_set_plain_is_empty(pw->p[i].set)) {
                        isl_set_free(pw->p[i].set);
                        FN(EL,free)(pw->p[i].FIELD);
                        if (i != pw->n - 1)
@@ -492,6 +492,9 @@ int FN(PW,involves_dims)(__isl_keep PW *pw, enum isl_dim_type type,
                                                        type, first, n);
                if (involves < 0 || involves)
                        return involves;
+               involves = isl_set_involves_dims(pw->p[i].set, type, first, n);
+               if (involves < 0 || involves)
+                       return involves;
        }
        return 0;
 }
diff --git a/isl_qsort.c b/isl_qsort.c
new file mode 100644 (file)
index 0000000..3183048
--- /dev/null
@@ -0,0 +1,249 @@
+/* Copyright (C) 1991,1992,1996,1997,1999,2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* If you consider tuning this algorithm, you should consult first:
+   Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
+   Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <isl_qsort.h>
+
+/* Byte-wise swap two items of size SIZE. */
+#define SWAP(a, b, size)                                                     \
+  do                                                                         \
+    {                                                                        \
+      register size_t __size = (size);                                       \
+      register char *__a = (a), *__b = (b);                                  \
+      do                                                                     \
+       {                                                                     \
+         char __tmp = *__a;                                                  \
+         *__a++ = *__b;                                                      \
+         *__b++ = __tmp;                                                     \
+       } while (--__size > 0);                                               \
+    } while (0)
+
+/* Discontinue quicksort algorithm when partition gets below this size.
+   This particular magic number was chosen to work best on a Sun 4/260. */
+#define MAX_THRESH 4
+
+/* Stack node declarations used to store unfulfilled partition obligations. */
+typedef struct
+  {
+    char *lo;
+    char *hi;
+  } stack_node;
+
+/* The next 4 #defines implement a very fast in-line stack abstraction. */
+/* The stack needs log (total_elements) entries (we could even subtract
+   log(MAX_THRESH)).  Since total_elements has type size_t, we get as
+   upper bound for log (total_elements):
+   bits per byte (CHAR_BIT) * sizeof(size_t).  */
+#define STACK_SIZE     (CHAR_BIT * sizeof(size_t))
+#define PUSH(low, high)        ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
+#define        POP(low, high)  ((void) (--top, (low = top->lo), (high = top->hi)))
+#define        STACK_NOT_EMPTY (stack < top)
+
+
+/* Order size using quicksort.  This implementation incorporates
+   four optimizations discussed in Sedgewick:
+
+   1. Non-recursive, using an explicit stack of pointer that store the
+      next array partition to sort.  To save time, this maximum amount
+      of space required to store an array of SIZE_MAX is allocated on the
+      stack.  Assuming a 32-bit (64 bit) integer for size_t, this needs
+      only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
+      Pretty cheap, actually.
+
+   2. Chose the pivot element using a median-of-three decision tree.
+      This reduces the probability of selecting a bad pivot value and
+      eliminates certain extraneous comparisons.
+
+   3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
+      insertion sort to order the MAX_THRESH items within each partition.
+      This is a big win, since insertion sort is faster for small, mostly
+      sorted array segments.
+
+   4. The larger of the two sub-partitions is always pushed onto the
+      stack first, with the algorithm then concentrating on the
+      smaller partition.  This *guarantees* no more than log (total_elems)
+      stack size is needed (actually O(1) in this case)!  */
+
+void isl_quicksort (void *const pbase, size_t total_elems, size_t size,
+       int (*cmp)(const void *, const void *, void *arg), void *arg)
+{
+  register char *base_ptr = (char *) pbase;
+
+  const size_t max_thresh = MAX_THRESH * size;
+
+  if (total_elems == 0)
+    /* Avoid lossage with unsigned arithmetic below.  */
+    return;
+
+  if (total_elems > MAX_THRESH)
+    {
+      char *lo = base_ptr;
+      char *hi = &lo[size * (total_elems - 1)];
+      stack_node stack[STACK_SIZE];
+      stack_node *top = stack;
+
+      PUSH (NULL, NULL);
+
+      while (STACK_NOT_EMPTY)
+        {
+          char *left_ptr;
+          char *right_ptr;
+
+         /* Select median value from among LO, MID, and HI. Rearrange
+            LO and HI so the three values are sorted. This lowers the
+            probability of picking a pathological pivot value and
+            skips a comparison for both the LEFT_PTR and RIGHT_PTR in
+            the while loops. */
+
+         char *mid = lo + size * ((hi - lo) / size >> 1);
+
+         if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
+           SWAP (mid, lo, size);
+         if ((*cmp) ((void *) hi, (void *) mid, arg) < 0)
+           SWAP (mid, hi, size);
+         else
+           goto jump_over;
+         if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
+           SWAP (mid, lo, size);
+       jump_over:;
+
+         left_ptr  = lo + size;
+         right_ptr = hi - size;
+
+         /* Here's the famous ``collapse the walls'' section of quicksort.
+            Gotta like those tight inner loops!  They are the main reason
+            that this algorithm runs much faster than others. */
+         do
+           {
+             while ((*cmp) ((void *) left_ptr, (void *) mid, arg) < 0)
+               left_ptr += size;
+
+             while ((*cmp) ((void *) mid, (void *) right_ptr, arg) < 0)
+               right_ptr -= size;
+
+             if (left_ptr < right_ptr)
+               {
+                 SWAP (left_ptr, right_ptr, size);
+                 if (mid == left_ptr)
+                   mid = right_ptr;
+                 else if (mid == right_ptr)
+                   mid = left_ptr;
+                 left_ptr += size;
+                 right_ptr -= size;
+               }
+             else if (left_ptr == right_ptr)
+               {
+                 left_ptr += size;
+                 right_ptr -= size;
+                 break;
+               }
+           }
+         while (left_ptr <= right_ptr);
+
+          /* Set up pointers for next iteration.  First determine whether
+             left and right partitions are below the threshold size.  If so,
+             ignore one or both.  Otherwise, push the larger partition's
+             bounds on the stack and continue sorting the smaller one. */
+
+          if ((size_t) (right_ptr - lo) <= max_thresh)
+            {
+              if ((size_t) (hi - left_ptr) <= max_thresh)
+               /* Ignore both small partitions. */
+                POP (lo, hi);
+              else
+               /* Ignore small left partition. */
+                lo = left_ptr;
+            }
+          else if ((size_t) (hi - left_ptr) <= max_thresh)
+           /* Ignore small right partition. */
+            hi = right_ptr;
+          else if ((right_ptr - lo) > (hi - left_ptr))
+            {
+             /* Push larger left partition indices. */
+              PUSH (lo, right_ptr);
+              lo = left_ptr;
+            }
+          else
+            {
+             /* Push larger right partition indices. */
+              PUSH (left_ptr, hi);
+              hi = right_ptr;
+            }
+        }
+    }
+
+  /* Once the BASE_PTR array is partially sorted by quicksort the rest
+     is completely sorted using insertion sort, since this is efficient
+     for partitions below MAX_THRESH size. BASE_PTR points to the beginning
+     of the array to sort, and END_PTR points at the very last element in
+     the array (*not* one beyond it!). */
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
+
+  {
+    char *const end_ptr = &base_ptr[size * (total_elems - 1)];
+    char *tmp_ptr = base_ptr;
+    char *thresh = min(end_ptr, base_ptr + max_thresh);
+    register char *run_ptr;
+
+    /* Find smallest element in first threshold and place it at the
+       array's beginning.  This is the smallest array element,
+       and the operation speeds up insertion sort's inner loop. */
+
+    for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
+      if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0)
+        tmp_ptr = run_ptr;
+
+    if (tmp_ptr != base_ptr)
+      SWAP (tmp_ptr, base_ptr, size);
+
+    /* Insertion sort, running from left-hand-side up to right-hand-side.  */
+
+    run_ptr = base_ptr + size;
+    while ((run_ptr += size) <= end_ptr)
+      {
+       tmp_ptr = run_ptr - size;
+       while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0)
+         tmp_ptr -= size;
+
+       tmp_ptr += size;
+        if (tmp_ptr != run_ptr)
+          {
+            char *trav;
+
+           trav = run_ptr + size;
+           while (--trav >= run_ptr)
+              {
+                char c = *trav;
+                char *hi, *lo;
+
+                for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
+                  *hi = *lo;
+                *hi = c;
+              }
+          }
+      }
+  }
+}
diff --git a/isl_qsort.h b/isl_qsort.h
new file mode 100644 (file)
index 0000000..5ca1634
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef ISL_QSORT_H
+#define ISL_QSORT_H
+
+void isl_quicksort (void *const pbase, size_t total_elems, size_t size,
+       int (*cmp)(const void *, const void *, void *arg), void *arg);
+
+#endif
index fd01261..9c9fb6d 100644 (file)
@@ -57,7 +57,7 @@ static struct isl_vec *interval_sample(struct isl_basic_set *bset)
        bset = isl_basic_set_simplify(bset);
        if (!bset)
                return NULL;
-       if (isl_basic_set_fast_is_empty(bset))
+       if (isl_basic_set_plain_is_empty(bset))
                return empty_sample(bset);
        if (bset->n_eq == 0 && bset->n_ineq == 0)
                return zero_sample(bset);
@@ -636,7 +636,7 @@ static struct isl_vec *sample_bounded(struct isl_basic_set *bset)
        if (!bset)
                return NULL;
 
-       if (isl_basic_set_fast_is_empty(bset))
+       if (isl_basic_set_plain_is_empty(bset))
                return empty_sample(bset);
 
        dim = isl_basic_set_total_dim(bset);
@@ -963,7 +963,7 @@ __isl_give isl_vec *isl_basic_set_sample_with_cone(
        total = isl_basic_set_total_dim(cone);
        cone_dim = total - cone->n_eq;
 
-       M = isl_mat_sub_alloc(bset->ctx, cone->eq, 0, cone->n_eq, 1, total);
+       M = isl_mat_sub_alloc6(bset->ctx, cone->eq, 0, cone->n_eq, 1, total);
        M = isl_mat_left_hermite(M, 0, &U, NULL);
        if (!M)
                goto error;
@@ -1178,7 +1178,7 @@ static struct isl_vec *basic_set_sample(struct isl_basic_set *bset, int bounded)
                return NULL;
 
        ctx = bset->ctx;
-       if (isl_basic_set_fast_is_empty(bset))
+       if (isl_basic_set_plain_is_empty(bset))
                return empty_sample(bset);
 
        dim = isl_basic_set_n_dim(bset);
diff --git a/isl_schedule.c b/isl_schedule.c
new file mode 100644 (file)
index 0000000..66c0ed5
--- /dev/null
@@ -0,0 +1,2372 @@
+/*
+ * 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_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_dim_private.h>
+#include <isl/hash.h>
+#include <isl/constraint.h>
+#include <isl/schedule.h>
+#include <isl_mat_private.h>
+#include <isl/set.h>
+#include <isl/seq.h>
+#include <isl_tab.h>
+#include <isl_dim_map.h>
+#include <isl_hmap_map_basic_set.h>
+#include <isl_qsort.h>
+
+/*
+ * The scheduling algorithm implemented in this file was inspired by
+ * Bondhugula et al., "Automatic Transformations for Communication-Minimized
+ * Parallelization and Locality Optimization in the Polyhedral Model".
+ */
+
+
+/* The schedule for an individual domain, plus information about the bands.
+ * In particular, we keep track of the number of bands and for each
+ * band, the starting position of the next band.  The first band starts at
+ * position 0.
+ */
+struct isl_schedule_node {
+       isl_map *sched;
+       int      n_band;
+       int     *band_end;
+};
+
+/* Information about the computed schedule.
+ * n is the number of nodes/domains/statements.
+ * n_band is the maximal number of bands.
+ * n_total_row is the number of coordinates of the schedule.
+ * dim contains a description of the parameters.
+ */
+struct isl_schedule {
+       int n;
+       int n_band;
+       int n_total_row;
+       isl_dim *dim;
+
+       struct isl_schedule_node node[1];
+};
+
+/* Internal information about a node that is used during the construction
+ * of a schedule.
+ * dim represents the space in which the domain lives
+ * sched is a matrix representation of the schedule being constructed
+ *     for this node
+ * sched_map is an isl_map representation of the same (partial) schedule
+ *     sched_map may be NULL
+ * rank is the number of linearly independent rows in the linear part
+ *     of sched
+ * the columns of cmap represent a change of basis for the schedule
+ *     coefficients; the first rank columns span the linear part of
+ *     the schedule rows
+ * start is the first variable in the LP problem in the sequences that
+ *     represents the schedule coefficients of this node
+ * nvar is the dimension of the domain
+ * nparam is the number of parameters or 0 if we are not constructing
+ *     a parametric schedule
+ *
+ * scc is the index of SCC (or WCC) this node belongs to
+ *
+ * band contains the band index for each of the rows of the schedule
+ *
+ * index, min_index and on_stack are used during the SCC detection
+ * index represents the order in which nodes are visited.
+ * min_index is the index of the root of a (sub)component.
+ * on_stack indicates whether the node is currently on the stack.
+ */
+struct isl_sched_node {
+       isl_dim *dim;
+       isl_mat *sched;
+       isl_map *sched_map;
+       int      rank;
+       isl_mat *cmap;
+       int      start;
+       int      nvar;
+       int      nparam;
+
+       int      scc;
+
+       int     *band;
+
+       /* scc detection */
+       int      index;
+       int      min_index;
+       int      on_stack;
+};
+
+static int node_has_dim(const void *entry, const void *val)
+{
+       struct isl_sched_node *node = (struct isl_sched_node *)entry;
+       isl_dim *dim = (isl_dim *)val;
+
+       return isl_dim_equal(node->dim, dim);
+}
+
+/* An edge in the dependence graph.  An edge may be used to
+ * ensure validity of the generated schedule, to minimize the dependence
+ * distance or both
+ *
+ * map is the dependence relation
+ * src is the source node
+ * dst is the sink node
+ * validity is set if the edge is used to ensure correctness
+ * proximity is set if the edge is used to minimize dependence distances
+ *
+ * For validity edges, start and end mark the sequence of inequality
+ * constraints in the LP problem that encode the validity constraint
+ * corresponding to this edge.
+ */
+struct isl_sched_edge {
+       isl_map *map;
+
+       struct isl_sched_node *src;
+       struct isl_sched_node *dst;
+
+       int validity;
+       int proximity;
+
+       int start;
+       int end;
+};
+
+/* Internal information about the dependence graph used during
+ * the construction of the schedule.
+ *
+ * intra_hmap is a cache, mapping dependence relations to their dual,
+ *     for dependences from a node to itself
+ * inter_hmap is a cache, mapping dependence relations to their dual,
+ *     for dependences between distinct nodes
+ *
+ * n is the number of nodes
+ * node is the list of nodes
+ * maxvar is the maximal number of variables over all nodes
+ * n_row is the current (maximal) number of linearly independent
+ *     rows in the node schedules
+ * n_total_row is the current number of rows in the node schedules
+ * n_band is the current number of completed bands
+ * band_start is the starting row in the node schedules of the current band
+ * root is set if this graph is the original dependence graph,
+ *     without any splitting
+ *
+ * sorted contains a list of node indices sorted according to the
+ *     SCC to which a node belongs
+ *
+ * n_edge is the number of edges
+ * edge is the list of edges
+ * edge_table contains pointers into the edge array, hashed on the source
+ *     and sink spaces; the table only contains edges that represent
+ *     validity constraints (and that may or may not also represent proximity
+ *     constraints)
+ *
+ * node_table contains pointers into the node array, hashed on the space
+ *
+ * region contains a list of variable sequences that should be non-trivial
+ *
+ * lp contains the (I)LP problem used to obtain new schedule rows
+ *
+ * src_scc and dst_scc are the source and sink SCCs of an edge with
+ *     conflicting constraints
+ *
+ * scc, sp, index and stack are used during the detection of SCCs
+ * scc is the number of the next SCC
+ * stack contains the nodes on the path from the root to the current node
+ * sp is the stack pointer
+ * index is the index of the last node visited
+ */
+struct isl_sched_graph {
+       isl_hmap_map_basic_set *intra_hmap;
+       isl_hmap_map_basic_set *inter_hmap;
+
+       struct isl_sched_node *node;
+       int n;
+       int maxvar;
+       int n_row;
+
+       int *sorted;
+
+       int n_band;
+       int n_total_row;
+       int band_start;
+
+       int root;
+
+       struct isl_sched_edge *edge;
+       int n_edge;
+       struct isl_hash_table *edge_table;
+
+       struct isl_hash_table *node_table;
+       struct isl_region *region;
+
+       isl_basic_set *lp;
+
+       int src_scc;
+       int dst_scc;
+
+       /* scc detection */
+       int scc;
+       int sp;
+       int index;
+       int *stack;
+};
+
+/* Initialize node_table based on the list of nodes.
+ */
+static int graph_init_table(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+       int i;
+
+       graph->node_table = isl_hash_table_alloc(ctx, graph->n);
+       if (!graph->node_table)
+               return -1;
+
+       for (i = 0; i < graph->n; ++i) {
+               struct isl_hash_table_entry *entry;
+               uint32_t hash;
+
+               hash = isl_dim_get_hash(graph->node[i].dim);
+               entry = isl_hash_table_find(ctx, graph->node_table, hash,
+                                           &node_has_dim,
+                                           graph->node[i].dim, 1);
+               if (!entry)
+                       return -1;
+               entry->data = &graph->node[i];
+       }
+
+       return 0;
+}
+
+/* Return a pointer to the node that lives within the given space,
+ * or NULL if there is no such node.
+ */
+static struct isl_sched_node *graph_find_node(isl_ctx *ctx,
+       struct isl_sched_graph *graph, __isl_keep isl_dim *dim)
+{
+       struct isl_hash_table_entry *entry;
+       uint32_t hash;
+
+       hash = isl_dim_get_hash(dim);
+       entry = isl_hash_table_find(ctx, graph->node_table, hash,
+                                   &node_has_dim, dim, 0);
+
+       return entry ? entry->data : NULL;
+}
+
+static int edge_has_src_and_dst(const void *entry, const void *val)
+{
+       const struct isl_sched_edge *edge = entry;
+       const struct isl_sched_edge *temp = val;
+
+       return edge->src == temp->src && edge->dst == temp->dst;
+}
+
+/* Initialize edge_table based on the list of edges.
+ * Only edges with validity set are added to the table.
+ */
+static int graph_init_edge_table(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+       int i;
+
+       graph->edge_table = isl_hash_table_alloc(ctx, graph->n_edge);
+       if (!graph->edge_table)
+               return -1;
+
+       for (i = 0; i < graph->n_edge; ++i) {
+               struct isl_hash_table_entry *entry;
+               uint32_t hash;
+
+               if (!graph->edge[i].validity)
+                       continue;
+
+               hash = isl_hash_init();
+               hash = isl_hash_builtin(hash, graph->edge[i].src);
+               hash = isl_hash_builtin(hash, graph->edge[i].dst);
+               entry = isl_hash_table_find(ctx, graph->edge_table, hash,
+                                           &edge_has_src_and_dst,
+                                           &graph->edge[i], 1);
+               if (!entry)
+                       return -1;
+               entry->data = &graph->edge[i];
+       }
+
+       return 0;
+}
+
+/* Check whether the dependence graph has a (validity) edge
+ * between the given two nodes.
+ */
+static int graph_has_edge(struct isl_sched_graph *graph,
+       struct isl_sched_node *src, struct isl_sched_node *dst)
+{
+       isl_ctx *ctx = isl_dim_get_ctx(src->dim);
+       struct isl_hash_table_entry *entry;
+       uint32_t hash;
+       struct isl_sched_edge temp = { .src = src, .dst = dst };
+       struct isl_sched_edge *edge;
+       int empty;
+
+       hash = isl_hash_init();
+       hash = isl_hash_builtin(hash, temp.src);
+       hash = isl_hash_builtin(hash, temp.dst);
+       entry = isl_hash_table_find(ctx, graph->edge_table, hash,
+                                   &edge_has_src_and_dst, &temp, 0);
+       if (!entry)
+               return 0;
+
+       edge = entry->data;
+       empty = isl_map_plain_is_empty(edge->map);
+       if (empty < 0)
+               return -1;
+
+       return !empty;
+}
+
+static int graph_alloc(isl_ctx *ctx, struct isl_sched_graph *graph,
+       int n_node, int n_edge)
+{
+       int i;
+
+       graph->n = n_node;
+       graph->n_edge = n_edge;
+       graph->node = isl_calloc_array(ctx, struct isl_sched_node, graph->n);
+       graph->sorted = isl_calloc_array(ctx, int, graph->n);
+       graph->region = isl_alloc_array(ctx, struct isl_region, graph->n);
+       graph->stack = isl_alloc_array(ctx, int, graph->n);
+       graph->edge = isl_calloc_array(ctx,
+                                       struct isl_sched_edge, graph->n_edge);
+
+       graph->intra_hmap = isl_hmap_map_basic_set_alloc(ctx, 2 * n_edge);
+       graph->inter_hmap = isl_hmap_map_basic_set_alloc(ctx, 2 * n_edge);
+
+       if (!graph->node || !graph->region || !graph->stack || !graph->edge ||
+           !graph->sorted)
+               return -1;
+
+       for(i = 0; i < graph->n; ++i)
+               graph->sorted[i] = i;
+
+       return 0;
+}
+
+static void graph_free(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+       int i;
+
+       isl_hmap_map_basic_set_free(ctx, graph->intra_hmap);
+       isl_hmap_map_basic_set_free(ctx, graph->inter_hmap);
+
+       for (i = 0; i < graph->n; ++i) {
+               isl_dim_free(graph->node[i].dim);
+               isl_mat_free(graph->node[i].sched);
+               isl_map_free(graph->node[i].sched_map);
+               isl_mat_free(graph->node[i].cmap);
+               if (graph->root)
+                       free(graph->node[i].band);
+       }
+       free(graph->node);
+       free(graph->sorted);
+       for (i = 0; i < graph->n_edge; ++i)
+               isl_map_free(graph->edge[i].map);
+       free(graph->edge);
+       free(graph->region);
+       free(graph->stack);
+       isl_hash_table_free(ctx, graph->edge_table);
+       isl_hash_table_free(ctx, graph->node_table);
+       isl_basic_set_free(graph->lp);
+}
+
+/* Add a new node to the graph representing the given set.
+ */
+static int extract_node(__isl_take isl_set *set, void *user)
+{
+       int nvar, nparam;
+       isl_ctx *ctx;
+       isl_dim *dim;
+       isl_mat *sched;
+       struct isl_sched_graph *graph = user;
+       int *band;
+
+       ctx = isl_set_get_ctx(set);
+       dim = isl_set_get_dim(set);
+       isl_set_free(set);
+       nvar = isl_dim_size(dim, isl_dim_set);
+       nparam = isl_dim_size(dim, isl_dim_param);
+       if (!ctx->opt->schedule_parametric)
+               nparam = 0;
+       sched = isl_mat_alloc(ctx, 0, 1 + nparam + nvar);
+       graph->node[graph->n].dim = dim;
+       graph->node[graph->n].nvar = nvar;
+       graph->node[graph->n].nparam = nparam;
+       graph->node[graph->n].sched = sched;
+       graph->node[graph->n].sched_map = NULL;
+       band = isl_alloc_array(ctx, int, graph->n_edge + nvar);
+       graph->node[graph->n].band = band;
+       graph->n++;
+
+       if (!sched || !band)
+               return -1;
+
+       return 0;
+}
+
+/* Add a new edge to the graph based on the given map.
+ * Edges are first extracted from the validity dependences,
+ * from which the edge_table is constructed.
+ * Afterwards, the proximity dependences are added.  If a proximity
+ * dependence relation happens to be identical to one of the
+ * validity dependence relations added before, then we don't create
+ * a new edge, but instead mark the original edge as also representing
+ * a proximity dependence.
+ */
+static int extract_edge(__isl_take isl_map *map, void *user)
+{
+       isl_ctx *ctx = isl_map_get_ctx(map);
+       struct isl_sched_graph *graph = user;
+       struct isl_sched_node *src, *dst;
+       isl_dim *dim;
+
+       dim = isl_dim_domain(isl_map_get_dim(map));
+       src = graph_find_node(ctx, graph, dim);
+       isl_dim_free(dim);
+       dim = isl_dim_range(isl_map_get_dim(map));
+       dst = graph_find_node(ctx, graph, dim);
+       isl_dim_free(dim);
+
+       if (!src || !dst) {
+               isl_map_free(map);
+               return 0;
+       }
+
+       graph->edge[graph->n_edge].src = src;
+       graph->edge[graph->n_edge].dst = dst;
+       graph->edge[graph->n_edge].map = map;
+       graph->edge[graph->n_edge].validity = !graph->edge_table;
+       graph->edge[graph->n_edge].proximity = !!graph->edge_table;
+       graph->n_edge++;
+
+       if (graph->edge_table) {
+               uint32_t hash;
+               struct isl_hash_table_entry *entry;
+               struct isl_sched_edge *edge;
+               int is_equal;
+
+               hash = isl_hash_init();
+               hash = isl_hash_builtin(hash, src);
+               hash = isl_hash_builtin(hash, dst);
+               entry = isl_hash_table_find(ctx, graph->edge_table, hash,
+                                           &edge_has_src_and_dst,
+                                           &graph->edge[graph->n_edge - 1], 0);
+               if (!entry)
+                       return 0;
+               edge = entry->data;
+               is_equal = isl_map_plain_is_equal(map, edge->map);
+               if (is_equal < 0)
+                       return -1;
+               if (!is_equal)
+                       return 0;
+
+               graph->n_edge--;
+               edge->proximity = 1;
+               isl_map_free(map);
+       }
+
+       return 0;
+}
+
+/* Check whether there is a validity dependence from src to dst,
+ * forcing dst to follow src.
+ */
+static int node_follows(struct isl_sched_graph *graph, 
+       struct isl_sched_node *dst, struct isl_sched_node *src)
+{
+       return graph_has_edge(graph, src, dst);
+}
+
+/* Perform Tarjan's algorithm for computing the strongly connected components
+ * in the dependence graph (only validity edges).
+ * If directed is not set, we consider the graph to be undirected and
+ * we effectively compute the (weakly) connected components.
+ */
+static int detect_sccs_tarjan(struct isl_sched_graph *g, int i, int directed)
+{
+       int j;
+
+       g->node[i].index = g->index;
+       g->node[i].min_index = g->index;
+       g->node[i].on_stack = 1;
+       g->index++;
+       g->stack[g->sp++] = i;
+
+       for (j = g->n - 1; j >= 0; --j) {
+               int f;
+
+               if (j == i)
+                       continue;
+               if (g->node[j].index >= 0 &&
+                       (!g->node[j].on_stack ||
+                        g->node[j].index > g->node[i].min_index))
+                       continue;
+               
+               f = node_follows(g, &g->node[i], &g->node[j]);
+               if (f < 0)
+                       return -1;
+               if (!f && !directed) {
+                       f = node_follows(g, &g->node[j], &g->node[i]);
+                       if (f < 0)
+                               return -1;
+               }
+               if (!f)
+                       continue;
+               if (g->node[j].index < 0) {
+                       detect_sccs_tarjan(g, j, directed);
+                       if (g->node[j].min_index < g->node[i].min_index)
+                               g->node[i].min_index = g->node[j].min_index;
+               } else if (g->node[j].index < g->node[i].min_index)
+                       g->node[i].min_index = g->node[j].index;
+       }
+
+       if (g->node[i].index != g->node[i].min_index)
+               return 0;
+
+       do {
+               j = g->stack[--g->sp];
+               g->node[j].on_stack = 0;
+               g->node[j].scc = g->scc;
+       } while (j != i);
+       g->scc++;
+
+       return 0;
+}
+
+static int detect_ccs(struct isl_sched_graph *graph, int directed)
+{
+       int i;
+
+       graph->index = 0;
+       graph->sp = 0;
+       graph->scc = 0;
+       for (i = graph->n - 1; i >= 0; --i)
+               graph->node[i].index = -1;
+
+       for (i = graph->n - 1; i >= 0; --i) {
+               if (graph->node[i].index >= 0)
+                       continue;
+               if (detect_sccs_tarjan(graph, i, directed) < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+/* Apply Tarjan's algorithm to detect the strongly connected components
+ * in the dependence graph.
+ */
+static int detect_sccs(struct isl_sched_graph *graph)
+{
+       return detect_ccs(graph, 1);
+}
+
+/* Apply Tarjan's algorithm to detect the (weakly) connected components
+ * in the dependence graph.
+ */
+static int detect_wccs(struct isl_sched_graph *graph)
+{
+       return detect_ccs(graph, 0);
+}
+
+static int cmp_scc(const void *a, const void *b, void *data)
+{
+       struct isl_sched_graph *graph = data;
+       const int *i1 = a;
+       const int *i2 = b;
+
+       return graph->node[*i1].scc - graph->node[*i2].scc;
+}
+
+/* Sort the elements of graph->sorted according to the corresponding SCCs.
+ */
+static void sort_sccs(struct isl_sched_graph *graph)
+{
+       isl_quicksort(graph->sorted, graph->n, sizeof(int), &cmp_scc, graph);
+}
+
+/* Given a dependence relation R from a node to itself,
+ * construct the set of coefficients of valid constraints for elements
+ * in that dependence relation.
+ * In particular, the result contains tuples of coefficients
+ * c_0, c_n, c_x such that
+ *
+ *     c_0 + c_n n + c_x y - c_x x >= 0 for each (x,y) in R
+ *
+ * or, equivalently,
+ *
+ *     c_0 + c_n n + c_x d >= 0 for each d in delta R = { y - x | (x,y) in R }
+ *
+ * We choose here to compute the dual of delta R.
+ * Alternatively, we could have computed the dual of R, resulting
+ * in a set of tuples c_0, c_n, c_x, c_y, and then
+ * plugged in (c_0, c_n, c_x, -c_x).
+ */
+static __isl_give isl_basic_set *intra_coefficients(
+       struct isl_sched_graph *graph, __isl_take isl_map *map)
+{
+       isl_ctx *ctx = isl_map_get_ctx(map);
+       isl_set *delta;
+       isl_basic_set *coef;
+
+       if (isl_hmap_map_basic_set_has(ctx, graph->intra_hmap, map))
+               return isl_hmap_map_basic_set_get(ctx, graph->intra_hmap, map);
+
+       delta = isl_set_remove_divs(isl_map_deltas(isl_map_copy(map)));
+       coef = isl_set_coefficients(delta);
+       isl_hmap_map_basic_set_set(ctx, graph->intra_hmap, map,
+                                       isl_basic_set_copy(coef));
+
+       return coef;
+}
+
+/* Given a dependence relation R, * construct the set of coefficients
+ * of valid constraints for elements in that dependence relation.
+ * In particular, the result contains tuples of coefficients
+ * c_0, c_n, c_x, c_y such that
+ *
+ *     c_0 + c_n n + c_x x + c_y y >= 0 for each (x,y) in R
+ *
+ */
+static __isl_give isl_basic_set *inter_coefficients(
+       struct isl_sched_graph *graph, __isl_take isl_map *map)
+{
+       isl_ctx *ctx = isl_map_get_ctx(map);
+       isl_set *set;
+       isl_basic_set *coef;
+
+       if (isl_hmap_map_basic_set_has(ctx, graph->inter_hmap, map))
+               return isl_hmap_map_basic_set_get(ctx, graph->inter_hmap, map);
+
+       set = isl_map_wrap(isl_map_remove_divs(isl_map_copy(map)));
+       coef = isl_set_coefficients(set);
+       isl_hmap_map_basic_set_set(ctx, graph->inter_hmap, map,
+                                       isl_basic_set_copy(coef));
+
+       return coef;
+}
+
+/* Add constraints to graph->lp that force validity for the given
+ * dependence from a node i to itself.
+ * That is, add constraints that enforce
+ *
+ *     (c_i_0 + c_i_n n + c_i_x y) - (c_i_0 + c_i_n n + c_i_x x)
+ *     = c_i_x (y - x) >= 0
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x)
+ * of valid constraints for (y - x) and then plug in (0, 0, c_i_x^+ - c_i_x^-),
+ * where c_i_x = c_i_x^+ - c_i_x^-, with c_i_x^+ and c_i_x^- non-negative.
+ * In graph->lp, the c_i_x^- appear before their c_i_x^+ counterpart.
+ *
+ * Actually, we do not construct constraints for the c_i_x themselves,
+ * but for the coefficients of c_i_x written as a linear combination
+ * of the columns in node->cmap.
+ */
+static int add_intra_validity_constraints(struct isl_sched_graph *graph,
+       struct isl_sched_edge *edge)
+{
+       unsigned total;
+       isl_map *map = isl_map_copy(edge->map);
+       isl_ctx *ctx = isl_map_get_ctx(map);
+       isl_dim *dim;
+       isl_dim_map *dim_map;
+       isl_basic_set *coef;
+       struct isl_sched_node *node = edge->src;
+
+       coef = intra_coefficients(graph, map);
+
+       dim = isl_dim_domain(isl_dim_unwrap(isl_basic_set_get_dim(coef)));
+
+       coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+                   isl_dim_size(dim, isl_dim_set), isl_mat_copy(node->cmap));
+
+       total = isl_basic_set_total_dim(graph->lp);
+       dim_map = isl_dim_map_alloc(ctx, total);
+       isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 1, 2,
+                         isl_dim_size(dim, isl_dim_set), 1,
+                         node->nvar, -1);
+       isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 2, 2,
+                         isl_dim_size(dim, isl_dim_set), 1,
+                         node->nvar, 1);
+       graph->lp = isl_basic_set_extend_constraints(graph->lp,
+                       coef->n_eq, coef->n_ineq);
+       graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+                                                          coef, dim_map);
+       isl_dim_free(dim);
+
+       return 0;
+}
+
+/* Add constraints to graph->lp that force validity for the given
+ * dependence from node i to node j.
+ * That is, add constraints that enforce
+ *
+ *     (c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x) >= 0
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x, c_y)
+ * of valid constraints for R and then plug in
+ * (c_j_0 - c_i_0, c_j_n^+ - c_j_n^- - (c_i_n^+ - c_i_n^-),
+ *  c_j_x^+ - c_j_x^- - (c_i_x^+ - c_i_x^-)),
+ * where c_* = c_*^+ - c_*^-, with c_*^+ and c_*^- non-negative.
+ * In graph->lp, the c_*^- appear before their c_*^+ counterpart.
+ *
+ * Actually, we do not construct constraints for the c_*_x themselves,
+ * but for the coefficients of c_*_x written as a linear combination
+ * of the columns in node->cmap.
+ */
+static int add_inter_validity_constraints(struct isl_sched_graph *graph,
+       struct isl_sched_edge *edge)
+{
+       unsigned total;
+       isl_map *map = isl_map_copy(edge->map);
+       isl_ctx *ctx = isl_map_get_ctx(map);
+       isl_dim *dim;
+       isl_dim_map *dim_map;
+       isl_basic_set *coef;
+       struct isl_sched_node *src = edge->src;
+       struct isl_sched_node *dst = edge->dst;
+
+       coef = inter_coefficients(graph, map);
+
+       dim = isl_dim_domain(isl_dim_unwrap(isl_basic_set_get_dim(coef)));
+
+       coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+                   isl_dim_size(dim, isl_dim_set), isl_mat_copy(src->cmap));
+       coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+                   isl_dim_size(dim, isl_dim_set) + src->nvar,
+                   isl_mat_copy(dst->cmap));
+
+       total = isl_basic_set_total_dim(graph->lp);
+       dim_map = isl_dim_map_alloc(ctx, total);
+
+       isl_dim_map_range(dim_map, dst->start, 0, 0, 0, 1, 1);
+       isl_dim_map_range(dim_map, dst->start + 1, 2, 1, 1, dst->nparam, -1);
+       isl_dim_map_range(dim_map, dst->start + 2, 2, 1, 1, dst->nparam, 1);
+       isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 1, 2,
+                         isl_dim_size(dim, isl_dim_set) + src->nvar, 1,
+                         dst->nvar, -1);
+       isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 2, 2,
+                         isl_dim_size(dim, isl_dim_set) + src->nvar, 1,
+                         dst->nvar, 1);
+
+       isl_dim_map_range(dim_map, src->start, 0, 0, 0, 1, -1);
+       isl_dim_map_range(dim_map, src->start + 1, 2, 1, 1, src->nparam, 1);
+       isl_dim_map_range(dim_map, src->start + 2, 2, 1, 1, src->nparam, -1);
+       isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 1, 2,
+                         isl_dim_size(dim, isl_dim_set), 1,
+                         src->nvar, 1);
+       isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 2, 2,
+                         isl_dim_size(dim, isl_dim_set), 1,
+                         src->nvar, -1);
+
+       edge->start = graph->lp->n_ineq;
+       graph->lp = isl_basic_set_extend_constraints(graph->lp,
+                       coef->n_eq, coef->n_ineq);
+       graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+                                                          coef, dim_map);
+       isl_dim_free(dim);
+       edge->end = graph->lp->n_ineq;
+
+       return 0;
+}
+
+/* Add constraints to graph->lp that bound the dependence distance for the given
+ * dependence from a node i to itself.
+ * If s = 1, we add the constraint
+ *
+ *     c_i_x (y - x) <= m_0 + m_n n
+ *
+ * or
+ *
+ *     -c_i_x (y - x) + m_0 + m_n n >= 0
+ *
+ * for each (x,y) in R.
+ * If s = -1, we add the constraint
+ *
+ *     -c_i_x (y - x) <= m_0 + m_n n
+ *
+ * or
+ *
+ *     c_i_x (y - x) + m_0 + m_n n >= 0
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x)
+ * of valid constraints for (y - x) and then plug in (m_0, m_n, -s * c_i_x),
+ * with each coefficient (except m_0) represented as a pair of non-negative
+ * coefficients.
+ *
+ * Actually, we do not construct constraints for the c_i_x themselves,
+ * but for the coefficients of c_i_x written as a linear combination
+ * of the columns in node->cmap.
+ */
+static int add_intra_proximity_constraints(struct isl_sched_graph *graph,
+       struct isl_sched_edge *edge, int s)
+{
+       unsigned total;
+       unsigned nparam;
+       isl_map *map = isl_map_copy(edge->map);
+       isl_ctx *ctx = isl_map_get_ctx(map);
+       isl_dim *dim;
+       isl_dim_map *dim_map;
+       isl_basic_set *coef;
+       struct isl_sched_node *node = edge->src;
+
+       coef = intra_coefficients(graph, map);
+
+       dim = isl_dim_domain(isl_dim_unwrap(isl_basic_set_get_dim(coef)));
+
+       coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+                   isl_dim_size(dim, isl_dim_set), isl_mat_copy(node->cmap));
+
+       nparam = isl_dim_size(node->dim, isl_dim_param);
+       total = isl_basic_set_total_dim(graph->lp);
+       dim_map = isl_dim_map_alloc(ctx, total);
+       isl_dim_map_range(dim_map, 1, 0, 0, 0, 1, 1);
+       isl_dim_map_range(dim_map, 4, 2, 1, 1, nparam, -1);
+       isl_dim_map_range(dim_map, 5, 2, 1, 1, nparam, 1);
+       isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 1, 2,
+                         isl_dim_size(dim, isl_dim_set), 1,
+                         node->nvar, s);
+       isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 2, 2,
+                         isl_dim_size(dim, isl_dim_set), 1,
+                         node->nvar, -s);
+       graph->lp = isl_basic_set_extend_constraints(graph->lp,
+                       coef->n_eq, coef->n_ineq);
+       graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+                                                          coef, dim_map);
+       isl_dim_free(dim);
+
+       return 0;
+}
+
+/* Add constraints to graph->lp that bound the dependence distance for the given
+ * dependence from node i to node j.
+ * If s = 1, we add the constraint
+ *
+ *     (c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x)
+ *             <= m_0 + m_n n
+ *
+ * or
+ *
+ *     -(c_j_0 + c_j_n n + c_j_x y) + (c_i_0 + c_i_n n + c_i_x x) +
+ *             m_0 + m_n n >= 0
+ *
+ * for each (x,y) in R.
+ * If s = -1, we add the constraint
+ *
+ *     -((c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x))
+ *             <= m_0 + m_n n
+ *
+ * or
+ *
+ *     (c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x) +
+ *             m_0 + m_n n >= 0
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x, c_y)
+ * of valid constraints for R and then plug in
+ * (m_0 - s*c_j_0 + s*c_i_0, m_n - s*c_j_n + s*c_i_n,
+ *  -s*c_j_x+s*c_i_x)
+ * with each coefficient (except m_0, c_j_0 and c_i_0)
+ * represented as a pair of non-negative coefficients.
+ *
+ * Actually, we do not construct constraints for the c_*_x themselves,
+ * but for the coefficients of c_*_x written as a linear combination
+ * of the columns in node->cmap.
+ */
+static int add_inter_proximity_constraints(struct isl_sched_graph *graph,
+       struct isl_sched_edge *edge, int s)
+{
+       unsigned total;
+       unsigned nparam;
+       isl_map *map = isl_map_copy(edge->map);
+       isl_ctx *ctx = isl_map_get_ctx(map);
+       isl_dim *dim;
+       isl_dim_map *dim_map;
+       isl_basic_set *coef;
+       struct isl_sched_node *src = edge->src;
+       struct isl_sched_node *dst = edge->dst;
+
+       coef = inter_coefficients(graph, map);
+
+       dim = isl_dim_domain(isl_dim_unwrap(isl_basic_set_get_dim(coef)));
+
+       coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+                   isl_dim_size(dim, isl_dim_set), isl_mat_copy(src->cmap));
+       coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+                   isl_dim_size(dim, isl_dim_set) + src->nvar,
+                   isl_mat_copy(dst->cmap));
+
+       nparam = isl_dim_size(src->dim, isl_dim_param);
+       total = isl_basic_set_total_dim(graph->lp);
+       dim_map = isl_dim_map_alloc(ctx, total);
+
+       isl_dim_map_range(dim_map, 1, 0, 0, 0, 1, 1);
+       isl_dim_map_range(dim_map, 4, 2, 1, 1, nparam, -1);
+       isl_dim_map_range(dim_map, 5, 2, 1, 1, nparam, 1);
+
+       isl_dim_map_range(dim_map, dst->start, 0, 0, 0, 1, -s);
+       isl_dim_map_range(dim_map, dst->start + 1, 2, 1, 1, dst->nparam, s);
+       isl_dim_map_range(dim_map, dst->start + 2, 2, 1, 1, dst->nparam, -s);
+       isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 1, 2,
+                         isl_dim_size(dim, isl_dim_set) + src->nvar, 1,
+                         dst->nvar, s);
+       isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 2, 2,
+                         isl_dim_size(dim, isl_dim_set) + src->nvar, 1,
+                         dst->nvar, -s);
+
+       isl_dim_map_range(dim_map, src->start, 0, 0, 0, 1, s);
+       isl_dim_map_range(dim_map, src->start + 1, 2, 1, 1, src->nparam, -s);
+       isl_dim_map_range(dim_map, src->start + 2, 2, 1, 1, src->nparam, s);
+       isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 1, 2,
+                         isl_dim_size(dim, isl_dim_set), 1,
+                         src->nvar, -s);
+       isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 2, 2,
+                         isl_dim_size(dim, isl_dim_set), 1,
+                         src->nvar, s);
+
+       graph->lp = isl_basic_set_extend_constraints(graph->lp,
+                       coef->n_eq, coef->n_ineq);
+       graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+                                                          coef, dim_map);
+       isl_dim_free(dim);
+
+       return 0;
+}
+
+static int add_all_validity_constraints(struct isl_sched_graph *graph)
+{
+       int i;
+
+       for (i = 0; i < graph->n_edge; ++i) {
+               struct isl_sched_edge *edge= &graph->edge[i];
+               if (!edge->validity)
+                       continue;
+               if (edge->src != edge->dst)
+                       continue;
+               if (add_intra_validity_constraints(graph, edge) < 0)
+                       return -1;
+       }
+
+       for (i = 0; i < graph->n_edge; ++i) {
+               struct isl_sched_edge *edge = &graph->edge[i];
+               if (!edge->validity)
+                       continue;
+               if (edge->src == edge->dst)
+                       continue;
+               if (add_inter_validity_constraints(graph, edge) < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+/* Add constraints to graph->lp that bound the dependence distance
+ * for all dependence relations.
+ * If a given proximity dependence is identical to a validity
+ * dependence, then the dependence distance is already bounded
+ * from below (by zero), so we only need to bound the distance
+ * from above.
+ * Otherwise, we need to bound the distance both from above and from below.
+ */
+static int add_all_proximity_constraints(struct isl_sched_graph *graph)
+{
+       int i;
+
+       for (i = 0; i < graph->n_edge; ++i) {
+               struct isl_sched_edge *edge= &graph->edge[i];
+               if (!edge->proximity)
+                       continue;
+               if (edge->src == edge->dst &&
+                   add_intra_proximity_constraints(graph, edge, 1) < 0)
+                       return -1;
+               if (edge->src != edge->dst &&
+                   add_inter_proximity_constraints(graph, edge, 1) < 0)
+                       return -1;
+               if (edge->validity)
+                       continue;
+               if (edge->src == edge->dst &&
+                   add_intra_proximity_constraints(graph, edge, -1) < 0)
+                       return -1;
+               if (edge->src != edge->dst &&
+                   add_inter_proximity_constraints(graph, edge, -1) < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+/* Compute a basis for the rows in the linear part of the schedule
+ * and extend this basis to a full basis.  The remaining rows
+ * can then be used to force linear independence from the rows
+ * in the schedule.
+ *
+ * In particular, given the schedule rows S, we compute
+ *
+ *     S = H Q
+ *
+ * with H the Hermite normal form of S.  That is, all but the
+ * first rank columns of Q are zero and so each row in S is
+ * a linear combination of the first rank rows of Q.
+ * The matrix Q is then transposed because we will write the
+ * coefficients of the next schedule row as a column vector s
+ * and express this s as a linear combination s = Q c of the
+ * computed basis.
+ */
+static int node_update_cmap(struct isl_sched_node *node)
+{
+       isl_mat *H, *Q;
+       int n_row = isl_mat_rows(node->sched);
+
+       H = isl_mat_sub_alloc(node->sched, 0, n_row,
+                             1 + node->nparam, node->nvar);
+
+       H = isl_mat_left_hermite(H, 0, NULL, &Q);
+       isl_mat_free(node->cmap);
+       node->cmap = isl_mat_transpose(Q);
+       node->rank = isl_mat_initial_non_zero_cols(H);
+       isl_mat_free(H);
+
+       if (!node->cmap || node->rank < 0)
+               return -1;
+       return 0;
+}
+
+/* Count the number of equality and inequality constraints
+ * that will be added.  If once is set, then we count
+ * each edge exactly once.  Otherwise, we count as follows
+ * validity            -> 1 (>= 0)
+ * validity+proximity  -> 2 (>= 0 and upper bound)
+ * proximity           -> 2 (lower and upper bound)
+ */
+static int count_constraints(struct isl_sched_graph *graph,
+       int *n_eq, int *n_ineq, int once)
+{
+       int i;
+       isl_basic_set *coef;
+
+       *n_eq = *n_ineq = 0;
+       for (i = 0; i < graph->n_edge; ++i) {
+               struct isl_sched_edge *edge= &graph->edge[i];
+               isl_map *map = isl_map_copy(edge->map);
+               int f = once ? 1 : edge->proximity ? 2 : 1;
+
+               if (edge->src == edge->dst)
+                       coef = intra_coefficients(graph, map);
+               else
+                       coef = inter_coefficients(graph, map);
+               if (!coef)
+                       return -1;
+               *n_eq += f * coef->n_eq;
+               *n_ineq += f * coef->n_ineq;
+               isl_basic_set_free(coef);
+       }
+
+       return 0;
+}
+
+/* Construct an ILP problem for finding schedule coefficients
+ * that result in non-negative, but small dependence distances
+ * over all dependences.
+ * In particular, the dependence distances over proximity edges
+ * are bounded by m_0 + m_n n and we compute schedule coefficients
+ * with small values (preferably zero) of m_n and m_0.
+ *
+ * All variables of the ILP are non-negative.  The actual coefficients
+ * may be negative, so each coefficient is represented as the difference
+ * of two non-negative variables.  The negative part always appears
+ * immediately before the positive part.
+ * Other than that, the variables have the following order
+ *
+ *     - sum of positive and negative parts of m_n coefficients
+ *     - m_0
+ *     - sum of positive and negative parts of all c_n coefficients
+ *             (unconstrained when computing non-parametric schedules)
+ *     - sum of positive and negative parts of all c_x coefficients
+ *     - positive and negative parts of m_n coefficients
+ *     - for each node
+ *             - c_i_0
+ *             - positive and negative parts of c_i_n (if parametric)
+ *             - positive and negative parts of c_i_x
+ *
+ * The c_i_x are not represented directly, but through the columns of
+ * node->cmap.  That is, the computed values are for variable t_i_x
+ * such that c_i_x = Q t_i_x with Q equal to node->cmap.
+ *
+ * The constraints are those from the edges plus two or three equalities
+ * to express the sums.
+ */
+static int setup_lp(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+       int i, j;
+       int k;
+       unsigned nparam;
+       unsigned total;
+       isl_dim *dim;
+       int parametric;
+       int param_pos;
+       int n_eq, n_ineq;
+
+       parametric = ctx->opt->schedule_parametric;
+       nparam = isl_dim_size(graph->node[0].dim, isl_dim_param);
+       param_pos = 4;
+       total = param_pos + 2 * nparam;
+       for (i = 0; i < graph->n; ++i) {
+               struct isl_sched_node *node = &graph->node[graph->sorted[i]];
+               if (node_update_cmap(node) < 0)
+                       return -1;
+               node->start = total;
+               total += 1 + 2 * (node->nparam + node->nvar);
+       }
+
+       if (count_constraints(graph, &n_eq, &n_ineq, 0) < 0)
+               return -1;
+
+       dim = isl_dim_set_alloc(ctx, 0, total);
+       isl_basic_set_free(graph->lp);
+       n_eq += 2 + parametric;
+       graph->lp = isl_basic_set_alloc_dim(dim, 0, n_eq, n_ineq);
+
+       k = isl_basic_set_alloc_equality(graph->lp);
+       if (k < 0)
+               return -1;
+       isl_seq_clr(graph->lp->eq[k], 1 +  total);
+       isl_int_set_si(graph->lp->eq[k][1], -1);
+       for (i = 0; i < 2 * nparam; ++i)
+               isl_int_set_si(graph->lp->eq[k][1 + param_pos + i], 1);
+
+       if (parametric) {
+               k = isl_basic_set_alloc_equality(graph->lp);
+               if (k < 0)
+                       return -1;
+               isl_seq_clr(graph->lp->eq[k], 1 +  total);
+               isl_int_set_si(graph->lp->eq[k][3], -1);
+               for (i = 0; i < graph->n; ++i) {
+                       int pos = 1 + graph->node[i].start + 1;
+
+                       for (j = 0; j < 2 * graph->node[i].nparam; ++j)
+                               isl_int_set_si(graph->lp->eq[k][pos + j], 1);
+               }
+       }
+
+       k = isl_basic_set_alloc_equality(graph->lp);
+       if (k < 0)
+               return -1;
+       isl_seq_clr(graph->lp->eq[k], 1 +  total);
+       isl_int_set_si(graph->lp->eq[k][4], -1);
+       for (i = 0; i < graph->n; ++i) {
+               struct isl_sched_node *node = &graph->node[i];
+               int pos = 1 + node->start + 1 + 2 * node->nparam;
+
+               for (j = 0; j < 2 * node->nvar; ++j)
+                       isl_int_set_si(graph->lp->eq[k][pos + j], 1);
+       }
+
+       if (add_all_validity_constraints(graph) < 0)
+               return -1;
+       if (add_all_proximity_constraints(graph) < 0)
+               return -1;
+
+       return 0;
+}
+
+/* Analyze the conflicting constraint found by
+ * isl_tab_basic_set_non_trivial_lexmin.  If it corresponds to the validity
+ * constraint of one of the edges between distinct nodes, living, moreover
+ * in distinct SCCs, then record the source and sink SCC as this may
+ * be a good place to cut between SCCs.
+ */
+static int check_conflict(int con, void *user)
+{
+       int i;
+       struct isl_sched_graph *graph = user;
+
+       if (graph->src_scc >= 0)
+               return 0;
+
+       con -= graph->lp->n_eq;
+
+       if (con >= graph->lp->n_ineq)
+               return 0;
+
+       for (i = 0; i < graph->n_edge; ++i) {
+               if (!graph->edge[i].validity)
+                       continue;
+               if (graph->edge[i].src == graph->edge[i].dst)
+                       continue;
+               if (graph->edge[i].src->scc == graph->edge[i].dst->scc)
+                       continue;
+               if (graph->edge[i].start > con)
+                       continue;
+               if (graph->edge[i].end <= con)
+                       continue;
+               graph->src_scc = graph->edge[i].src->scc;
+               graph->dst_scc = graph->edge[i].dst->scc;
+       }
+
+       return 0;
+}
+
+/* Check whether the next schedule row of the given node needs to be
+ * non-trivial.  Lower-dimensional domains may have some trivial rows,
+ * but as soon as the number of remaining required non-trivial rows
+ * is as large as the number or remaining rows to be computed,
+ * all remaining rows need to be non-trivial.
+ */
+static int needs_row(struct isl_sched_graph *graph, struct isl_sched_node *node)
+{
+       return node->nvar - node->rank >= graph->maxvar - graph->n_row;
+}
+
+/* Solve the ILP problem constructed in setup_lp.
+ * For each node such that all the remaining rows of its schedule
+ * need to be non-trivial, we construct a non-triviality region.
+ * This region imposes that the next row is independent of previous rows.
+ * In particular the coefficients c_i_x are represented by t_i_x
+ * variables with c_i_x = Q t_i_x and Q a unimodular matrix such that
+ * its first columns span the rows of the previously computed part
+ * of the schedule.  The non-triviality region enforces that at least
+ * one of the remaining components of t_i_x is non-zero, i.e.,
+ * that the new schedule row depends on at least one of the remaining
+ * columns of Q.
+ */
+static __isl_give isl_vec *solve_lp(struct isl_sched_graph *graph)
+{
+       int i;
+       isl_vec *sol;
+       isl_basic_set *lp;
+
+       for (i = 0; i < graph->n; ++i) {
+               struct isl_sched_node *node = &graph->node[i];
+               int skip = node->rank;
+               graph->region[i].pos = node->start + 1 + 2*(node->nparam+skip);
+               if (needs_row(graph, node))
+                       graph->region[i].len = 2 * (node->nvar - skip);
+               else
+                       graph->region[i].len = 0;
+       }
+       lp = isl_basic_set_copy(graph->lp);
+       sol = isl_tab_basic_set_non_trivial_lexmin(lp, 2, graph->n,
+                                      graph->region, &check_conflict, graph);
+       return sol;
+}
+
+/* Update the schedules of all nodes based on the given solution
+ * of the LP problem.
+ * The new row is added to the current band.
+ * All possibly negative coefficients are encoded as a difference
+ * of two non-negative variables, so we need to perform the subtraction
+ * here.  Moreover, if use_cmap is set, then the solution does
+ * not refer to the actual coefficients c_i_x, but instead to variables
+ * t_i_x such that c_i_x = Q t_i_x and Q is equal to node->cmap.
+ * In this case, we then also need to perform this multiplication
+ * to obtain the values of c_i_x.
+ */
+static int update_schedule(struct isl_sched_graph *graph,
+       __isl_take isl_vec *sol, int use_cmap)
+{
+       int i, j;
+       isl_vec *csol = NULL;
+
+       if (!sol)
+               goto error;
+       if (sol->size == 0)
+               isl_die(sol->ctx, isl_error_internal,
+                       "no solution found", goto error);
+
+       for (i = 0; i < graph->n; ++i) {
+               struct isl_sched_node *node = &graph->node[i];
+               int pos = node->start;
+               int row = isl_mat_rows(node->sched);
+
+               isl_vec_free(csol);
+               csol = isl_vec_alloc(sol->ctx, node->nvar);
+               if (!csol)
+                       goto error;
+
+               isl_map_free(node->sched_map);
+               node->sched_map = NULL;
+               node->sched = isl_mat_add_rows(node->sched, 1);
+               if (!node->sched)
+                       goto error;
+               node->sched = isl_mat_set_element(node->sched, row, 0,
+                                                 sol->el[1 + pos]);
+               for (j = 0; j < node->nparam + node->nvar; ++j)
+                       isl_int_sub(sol->el[1 + pos + 1 + 2 * j + 1],
+                                   sol->el[1 + pos + 1 + 2 * j + 1],
+                                   sol->el[1 + pos + 1 + 2 * j]);
+               for (j = 0; j < node->nparam; ++j)
+                       node->sched = isl_mat_set_element(node->sched,
+                                       row, 1 + j, sol->el[1+pos+1+2*j+1]);
+               for (j = 0; j < node->nvar; ++j)
+                       isl_int_set(csol->el[j],
+                                   sol->el[1+pos+1+2*(node->nparam+j)+1]);
+               if (use_cmap)
+                       csol = isl_mat_vec_product(isl_mat_copy(node->cmap),
+                                                  csol);
+               if (!csol)
+                       goto error;
+               for (j = 0; j < node->nvar; ++j)
+                       node->sched = isl_mat_set_element(node->sched,
+                                       row, 1 + node->nparam + j, csol->el[j]);
+               node->band[graph->n_total_row] = graph->n_band;
+       }
+       isl_vec_free(sol);
+       isl_vec_free(csol);
+
+       graph->n_row++;
+       graph->n_total_row++;
+
+       return 0;
+error:
+       isl_vec_free(sol);
+       isl_vec_free(csol);
+       return -1;
+}
+
+/* Convert node->sched into a map and return this map.
+ * We simply add equality constraints that express each output variable
+ * as the affine combination of parameters and input variables specified
+ * by the schedule matrix.
+ *
+ * The result is cached in node->sched_map, which needs to be released
+ * whenever node->sched is updated.
+ */
+static __isl_give isl_map *node_extract_schedule(struct isl_sched_node *node)
+{
+       int i, j;
+       isl_dim *dim;
+       isl_basic_map *bmap;
+       isl_constraint *c;
+       int nrow, ncol;
+       isl_int v;
+
+       if (node->sched_map)
+               return isl_map_copy(node->sched_map);
+
+       nrow = isl_mat_rows(node->sched);
+       ncol = isl_mat_cols(node->sched) - 1;
+       dim = isl_dim_from_domain(isl_dim_copy(node->dim));
+       dim = isl_dim_add(dim, isl_dim_out, nrow);
+       bmap = isl_basic_map_universe(isl_dim_copy(dim));
+
+       isl_int_init(v);
+
+       for (i = 0; i < nrow; ++i) {
+               c = isl_equality_alloc(isl_dim_copy(dim));
+               isl_constraint_set_coefficient_si(c, isl_dim_out, i, -1);
+               isl_mat_get_element(node->sched, i, 0, &v);
+               isl_constraint_set_constant(c, v);
+               for (j = 0; j < node->nparam; ++j) {
+                       isl_mat_get_element(node->sched, i, 1 + j, &v);
+                       isl_constraint_set_coefficient(c, isl_dim_param, j, v);
+               }
+               for (j = 0; j < node->nvar; ++j) {
+                       isl_mat_get_element(node->sched,
+                                           i, 1 + node->nparam + j, &v);
+                       isl_constraint_set_coefficient(c, isl_dim_in, j, v);
+               }
+               bmap = isl_basic_map_add_constraint(bmap, c);
+       }
+
+       isl_int_clear(v);
+
+       isl_dim_free(dim);
+
+       node->sched_map = isl_map_from_basic_map(bmap);
+       return isl_map_copy(node->sched_map);
+}
+
+/* Update the given dependence relation based on the current schedule.
+ * That is, intersect the dependence relation with a map expressing
+ * that source and sink are executed within the same iteration of
+ * the current schedule.
+ * This is not the most efficient way, but this shouldn't be a critical
+ * operation.
+ */
+static __isl_give isl_map *specialize(__isl_take isl_map *map,
+       struct isl_sched_node *src, struct isl_sched_node *dst)
+{
+       isl_map *src_sched, *dst_sched, *id;
+
+       src_sched = node_extract_schedule(src);
+       dst_sched = node_extract_schedule(dst);
+       id = isl_map_apply_range(src_sched, isl_map_reverse(dst_sched));
+       return isl_map_intersect(map, id);
+}
+
+/* Update the dependence relations of all edges based on the current schedule.
+ * If a dependence is carried completely by the current schedule, then
+ * it is removed and edge_table is updated accordingly.
+ */
+static int update_edges(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+       int i;
+       int reset_table = 0;
+
+       for (i = graph->n_edge - 1; i >= 0; --i) {
+               struct isl_sched_edge *edge = &graph->edge[i];
+               edge->map = specialize(edge->map, edge->src, edge->dst);
+               if (!edge->map)
+                       return -1;
+
+               if (isl_map_plain_is_empty(edge->map)) {
+                       reset_table = 1;
+                       isl_map_free(edge->map);
+                       if (i != graph->n_edge - 1)
+                               graph->edge[i] = graph->edge[graph->n_edge - 1];
+                       graph->n_edge--;
+               }
+       }
+
+       if (reset_table) {
+               isl_hash_table_free(ctx, graph->edge_table);
+               graph->edge_table = NULL;
+               return graph_init_edge_table(ctx, graph);
+       }
+
+       return 0;
+}
+
+static void next_band(struct isl_sched_graph *graph)
+{
+       graph->band_start = graph->n_total_row;
+       graph->n_band++;
+}
+
+/* Topologically sort statements mapped to same schedule iteration
+ * and add a row to the schedule corresponding to this order.
+ */
+static int sort_statements(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+       int i, j;
+
+       if (graph->n <= 1)
+               return 0;
+
+       if (update_edges(ctx, graph) < 0)
+               return -1;
+
+       if (graph->n_edge == 0)
+               return 0;
+
+       if (detect_sccs(graph) < 0)
+               return -1;
+
+       for (i = 0; i < graph->n; ++i) {
+               struct isl_sched_node *node = &graph->node[i];
+               int row = isl_mat_rows(node->sched);
+               int cols = isl_mat_cols(node->sched);
+
+               isl_map_free(node->sched_map);
+               node->sched_map = NULL;
+               node->sched = isl_mat_add_rows(node->sched, 1);
+               if (!node->sched)
+                       return -1;
+               node->sched = isl_mat_set_element_si(node->sched, row, 0,
+                                                    node->scc);
+               for (j = 1; j < cols; ++j)
+                       node->sched = isl_mat_set_element_si(node->sched,
+                                                            row, j, 0);
+               node->band[graph->n_total_row] = graph->n_band;
+       }
+
+       graph->n_total_row++;
+       next_band(graph);
+
+       return 0;
+}
+
+/* Construct an isl_schedule based on the computed schedule stored
+ * in graph and with parameters specified by dim.
+ */
+static __isl_give isl_schedule *extract_schedule(struct isl_sched_graph *graph,
+       __isl_take isl_dim *dim)
+{
+       int i;
+       isl_ctx *ctx;
+       isl_schedule *sched = NULL;
+               
+       if (!dim)
+               return NULL;
+
+       ctx = isl_dim_get_ctx(dim);
+       sched = isl_calloc(ctx, struct isl_schedule,
+                          sizeof(struct isl_schedule) +
+                          (graph->n - 1) * sizeof(struct isl_schedule_node));
+       if (!sched)
+               goto error;
+
+       sched->n = graph->n;
+       sched->n_band = graph->n_band;
+       sched->n_total_row = graph->n_total_row;
+
+       for (i = 0; i < sched->n; ++i) {
+               int r, b;
+               int *band_end;
+
+               band_end = isl_alloc_array(ctx, int, graph->n_band);
+               if (!band_end)
+                       goto error;
+               sched->node[i].sched = node_extract_schedule(&graph->node[i]);
+               sched->node[i].band_end = band_end;
+
+               for (r = b = 0; r < graph->n_total_row; ++r) {
+                       if (graph->node[i].band[r] == b)
+                               continue;
+                       band_end[b++] = r;
+                       if (graph->node[i].band[r] == -1)
+                               break;
+               }
+               if (r == graph->n_total_row)
+                       band_end[b++] = r;
+               sched->node[i].n_band = b;
+       }
+
+       sched->dim = dim;
+
+       return sched;
+error:
+       isl_dim_free(dim);
+       isl_schedule_free(sched);
+       return NULL;
+}
+
+/* Copy nodes that satisfy node_pred from the src dependence graph
+ * to the dst dependence graph.
+ */
+static int copy_nodes(struct isl_sched_graph *dst, struct isl_sched_graph *src,
+       int (*node_pred)(struct isl_sched_node *node, int data), int data)
+{
+       int i;
+
+       dst->n = 0;
+       for (i = 0; i < src->n; ++i) {
+               if (!node_pred(&src->node[i], data))
+                       continue;
+               dst->node[dst->n].dim = isl_dim_copy(src->node[i].dim);
+               dst->node[dst->n].nvar = src->node[i].nvar;
+               dst->node[dst->n].nparam = src->node[i].nparam;
+               dst->node[dst->n].sched = isl_mat_copy(src->node[i].sched);
+               dst->node[dst->n].sched_map =
+                       isl_map_copy(src->node[i].sched_map);
+               dst->node[dst->n].band = src->node[i].band;
+               dst->n++;
+       }
+
+       return 0;
+}
+
+/* Copy non-empty edges that satisfy edge_pred from the src dependence graph
+ * to the dst dependence graph.
+ */
+static int copy_edges(isl_ctx *ctx, struct isl_sched_graph *dst,
+       struct isl_sched_graph *src,
+       int (*edge_pred)(struct isl_sched_edge *edge, int data), int data)
+{
+       int i;
+
+       dst->n_edge = 0;
+       for (i = 0; i < src->n_edge; ++i) {
+               struct isl_sched_edge *edge = &src->edge[i];
+               isl_map *map;
+
+               if (!edge_pred(edge, data))
+                       continue;
+
+               if (isl_map_plain_is_empty(edge->map))
+                       continue;
+
+               map = isl_map_copy(edge->map);
+
+               dst->edge[dst->n_edge].src =
+                       graph_find_node(ctx, dst, edge->src->dim);
+               dst->edge[dst->n_edge].dst =
+                       graph_find_node(ctx, dst, edge->dst->dim);
+               dst->edge[dst->n_edge].map = map;
+               dst->edge[dst->n_edge].validity = edge->validity;
+               dst->edge[dst->n_edge].proximity = edge->proximity;
+               dst->n_edge++;
+       }
+
+       return 0;
+}
+
+/* Given a "src" dependence graph that contains the nodes from "dst"
+ * that satisfy node_pred, copy the schedule computed in "src"
+ * for those nodes back to "dst".
+ */
+static int copy_schedule(struct isl_sched_graph *dst,
+       struct isl_sched_graph *src,
+       int (*node_pred)(struct isl_sched_node *node, int data), int data)
+{
+       int i;
+
+       src->n = 0;
+       for (i = 0; i < dst->n; ++i) {
+               if (!node_pred(&dst->node[i], data))
+                       continue;
+               isl_mat_free(dst->node[i].sched);
+               isl_map_free(dst->node[i].sched_map);
+               dst->node[i].sched = isl_mat_copy(src->node[src->n].sched);
+               dst->node[i].sched_map =
+                       isl_map_copy(src->node[src->n].sched_map);
+               src->n++;
+       }
+
+       dst->n_total_row = src->n_total_row;
+       dst->n_band = src->n_band;
+
+       return 0;
+}
+
+/* Compute the maximal number of variables over all nodes.
+ * This is the maximal number of linearly independent schedule
+ * rows that we need to compute.
+ * Just in case we end up in a part of the dependence graph
+ * with only lower-dimensional domains, we make sure we will
+ * compute the required amount of extra linearly independent rows.
+ */
+static int compute_maxvar(struct isl_sched_graph *graph)
+{
+       int i;
+
+       graph->maxvar = 0;
+       for (i = 0; i < graph->n; ++i) {
+               struct isl_sched_node *node = &graph->node[i];
+               int nvar;
+
+               if (node_update_cmap(node) < 0)
+                       return -1;
+               nvar = node->nvar + graph->n_row - node->rank;
+               if (nvar > graph->maxvar)
+                       graph->maxvar = nvar;
+       }
+
+       return 0;
+}
+
+static int compute_schedule(isl_ctx *ctx, struct isl_sched_graph *graph);
+static int compute_schedule_wcc(isl_ctx *ctx, struct isl_sched_graph *graph);
+
+/* Compute a schedule for a subgraph of "graph".  In particular, for
+ * the graph composed of nodes that satisfy node_pred and edges that
+ * that satisfy edge_pred.  The caller should precompute the number
+ * of nodes and edges that satisfy these predicates and pass them along
+ * as "n" and "n_edge".
+ * If the subgraph is known to consist of a single component, then wcc should
+ * be set and then we call compute_schedule_wcc on the constructed subgraph.
+ * Otherwise, we call compute_schedule, which will check whether the subgraph
+ * is connected.
+ */
+static int compute_sub_schedule(isl_ctx *ctx,
+       struct isl_sched_graph *graph, int n, int n_edge,
+       int (*node_pred)(struct isl_sched_node *node, int data),
+       int (*edge_pred)(struct isl_sched_edge *edge, int data),
+       int data, int wcc)
+{
+       struct isl_sched_graph split = { 0 };
+
+       if (graph_alloc(ctx, &split, n, n_edge) < 0)
+               goto error;
+       if (copy_nodes(&split, graph, node_pred, data) < 0)
+               goto error;
+       if (graph_init_table(ctx, &split) < 0)
+               goto error;
+       if (copy_edges(ctx, &split, graph, edge_pred, data) < 0)
+               goto error;
+       if (graph_init_edge_table(ctx, &split) < 0)
+               goto error;
+       split.n_row = graph->n_row;
+       split.n_total_row = graph->n_total_row;
+       split.n_band = graph->n_band;
+       split.band_start = graph->band_start;
+
+       if (wcc && compute_schedule_wcc(ctx, &split) < 0)
+               goto error;
+       if (!wcc && compute_schedule(ctx, &split) < 0)
+               goto error;
+
+       copy_schedule(graph, &split, node_pred, data);
+
+       graph_free(ctx, &split);
+       return 0;
+error:
+       graph_free(ctx, &split);
+       return -1;
+}
+
+static int node_scc_exactly(struct isl_sched_node *node, int scc)
+{
+       return node->scc == scc;
+}
+
+static int node_scc_at_most(struct isl_sched_node *node, int scc)
+{
+       return node->scc <= scc;
+}
+
+static int node_scc_at_least(struct isl_sched_node *node, int scc)
+{
+       return node->scc >= scc;
+}
+
+static int edge_src_scc_exactly(struct isl_sched_edge *edge, int scc)
+{
+       return edge->src->scc == scc;
+}
+
+static int edge_dst_scc_at_most(struct isl_sched_edge *edge, int scc)
+{
+       return edge->dst->scc <= scc;
+}
+
+static int edge_src_scc_at_least(struct isl_sched_edge *edge, int scc)
+{
+       return edge->src->scc >= scc;
+}
+
+/* Pad the schedules of all nodes with zero rows such that in the end
+ * they all have graph->n_total_row rows.
+ * The extra rows don't belong to any band, so they get assigned band number -1.
+ */
+static int pad_schedule(struct isl_sched_graph *graph)
+{
+       int i, j;
+
+       for (i = 0; i < graph->n; ++i) {
+               struct isl_sched_node *node = &graph->node[i];
+               int row = isl_mat_rows(node->sched);
+               if (graph->n_total_row > row) {
+                       isl_map_free(node->sched_map);
+                       node->sched_map = NULL;
+               }
+               node->sched = isl_mat_add_zero_rows(node->sched,
+                                                   graph->n_total_row - row);
+               if (!node->sched)
+                       return -1;
+               for (j = row; j < graph->n_total_row; ++j)
+                       node->band[j] = -1;
+       }
+
+       return 0;
+}
+
+/* Split the current graph into two parts and compute a schedule for each
+ * part individually.  In particular, one part consists of all SCCs up
+ * to and including graph->src_scc, while the other part contains the other
+ * SCCS.
+ *
+ * The split is enforced in the schedule by constant rows with two different
+ * values (0 and 1).  These constant rows replace the previously computed rows
+ * in the current band.
+ * It would be possible to reuse them as the first rows in the next
+ * band, but recomputing them may result in better rows as we are looking
+ * at a smaller part of the dependence graph.
+ */
+static int compute_split_schedule(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+       int i, j, n, e1, e2;
+       int n_total_row, orig_total_row;
+       int n_band, orig_band;
+       int drop;
+
+       drop = graph->n_total_row - graph->band_start;
+       graph->n_total_row -= drop;
+       graph->n_row -= drop;
+
+       n = 0;
+       for (i = 0; i < graph->n; ++i) {
+               struct isl_sched_node *node = &graph->node[i];
+               int row = isl_mat_rows(node->sched) - drop;
+               int cols = isl_mat_cols(node->sched);
+               int before = node->scc <= graph->src_scc;
+
+               if (before)
+                       n++;
+
+               isl_map_free(node->sched_map);
+               node->sched_map = NULL;
+               node->sched = isl_mat_drop_rows(node->sched,
+                                               graph->band_start, drop);
+               node->sched = isl_mat_add_rows(node->sched, 1);
+               if (!node->sched)
+                       return -1;
+               node->sched = isl_mat_set_element_si(node->sched, row, 0,
+                                                    !before);
+               for (j = 1; j < cols; ++j)
+                       node->sched = isl_mat_set_element_si(node->sched,
+                                                            row, j, 0);
+               node->band[graph->n_total_row] = graph->n_band;
+       }
+
+       e1 = e2 = 0;
+       for (i = 0; i < graph->n_edge; ++i) {
+               if (graph->edge[i].dst->scc <= graph->src_scc)
+                       e1++;
+               if (graph->edge[i].src->scc > graph->src_scc)
+                       e2++;
+       }
+
+       graph->n_total_row++;
+       next_band(graph);
+
+       orig_total_row = graph->n_total_row;
+       orig_band = graph->n_band;
+       if (compute_sub_schedule(ctx, graph, n, e1,
+                               &node_scc_at_most, &edge_dst_scc_at_most,
+                               graph->src_scc, 0) < 0)
+               return -1;
+       n_total_row = graph->n_total_row;
+       graph->n_total_row = orig_total_row;
+       n_band = graph->n_band;
+       graph->n_band = orig_band;
+       if (compute_sub_schedule(ctx, graph, graph->n - n, e2,
+                               &node_scc_at_least, &edge_src_scc_at_least,
+                               graph->src_scc + 1, 0) < 0)
+               return -1;
+       if (n_total_row > graph->n_total_row)
+               graph->n_total_row = n_total_row;
+       if (n_band > graph->n_band)
+               graph->n_band = n_band;
+
+       return pad_schedule(graph);
+}
+
+/* Compute the next band of the schedule after updating the dependence
+ * relations based on the the current schedule.
+ */
+static int compute_next_band(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+       if (update_edges(ctx, graph) < 0)
+               return -1;
+       next_band(graph);
+               
+       return compute_schedule(ctx, graph);
+}
+
+/* Add constraints to graph->lp that force the dependence of edge i
+ * to be respected and attempt to carry it, where edge i is one from
+ * a node j to itself.
+ * That is, add constraints that enforce
+ *
+ *     (c_j_0 + c_j_n n + c_j_x y) - (c_j_0 + c_j_n n + c_j_x x)
+ *     = c_j_x (y - x) >= e_i
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x)
+ * of valid constraints for (y - x) and then plug in (-e_i, 0, c_j_x),
+ * with each coefficient in c_j_x represented as a pair of non-negative
+ * coefficients.
+ */
+static int add_intra_constraints(struct isl_sched_graph *graph, int i)
+{
+       unsigned total;
+       struct isl_sched_edge *edge= &graph->edge[i];
+       isl_map *map = isl_map_copy(edge->map);
+       isl_ctx *ctx = isl_map_get_ctx(map);
+       isl_dim *dim;
+       isl_dim_map *dim_map;
+       isl_basic_set *coef;
+       struct isl_sched_node *node = edge->src;
+
+       coef = intra_coefficients(graph, map);
+
+       dim = isl_dim_domain(isl_dim_unwrap(isl_basic_set_get_dim(coef)));
+
+       total = isl_basic_set_total_dim(graph->lp);
+       dim_map = isl_dim_map_alloc(ctx, total);
+       isl_dim_map_range(dim_map, 3 + i, 0, 0, 0, 1, -1);
+       isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 1, 2,
+                         isl_dim_size(dim, isl_dim_set), 1,
+                         node->nvar, -1);
+       isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 2, 2,
+                         isl_dim_size(dim, isl_dim_set), 1,
+                         node->nvar, 1);
+       graph->lp = isl_basic_set_extend_constraints(graph->lp,
+                       coef->n_eq, coef->n_ineq);
+       graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+                                                          coef, dim_map);
+       isl_dim_free(dim);
+
+       return 0;
+}
+
+/* Add constraints to graph->lp that force the dependence of edge i
+ * to be respected and attempt to carry it, where edge i is one from
+ * node j to node k.
+ * That is, add constraints that enforce
+ *
+ *     (c_k_0 + c_k_n n + c_k_x y) - (c_j_0 + c_j_n n + c_j_x x) >= e_i
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x)
+ * of valid constraints for R and then plug in
+ * (-e_i + c_k_0 - c_j_0, c_k_n - c_j_n, c_k_x - c_j_x)
+ * with each coefficient (except e_i, c_k_0 and c_j_0)
+ * represented as a pair of non-negative coefficients.
+ */
+static int add_inter_constraints(struct isl_sched_graph *graph, int i)
+{
+       unsigned total;
+       struct isl_sched_edge *edge= &graph->edge[i];
+       isl_map *map = isl_map_copy(edge->map);
+       isl_ctx *ctx = isl_map_get_ctx(map);
+       isl_dim *dim;
+       isl_dim_map *dim_map;
+       isl_basic_set *coef;
+       struct isl_sched_node *src = edge->src;
+       struct isl_sched_node *dst = edge->dst;
+
+       coef = inter_coefficients(graph, map);
+
+       dim = isl_dim_domain(isl_dim_unwrap(isl_basic_set_get_dim(coef)));
+
+       total = isl_basic_set_total_dim(graph->lp);
+       dim_map = isl_dim_map_alloc(ctx, total);
+
+       isl_dim_map_range(dim_map, 3 + i, 0, 0, 0, 1, -1);
+
+       isl_dim_map_range(dim_map, dst->start, 0, 0, 0, 1, 1);
+       isl_dim_map_range(dim_map, dst->start + 1, 2, 1, 1, dst->nparam, -1);
+       isl_dim_map_range(dim_map, dst->start + 2, 2, 1, 1, dst->nparam, 1);
+       isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 1, 2,
+                         isl_dim_size(dim, isl_dim_set) + src->nvar, 1,
+                         dst->nvar, -1);
+       isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 2, 2,
+                         isl_dim_size(dim, isl_dim_set) + src->nvar, 1,
+                         dst->nvar, 1);
+
+       isl_dim_map_range(dim_map, src->start, 0, 0, 0, 1, -1);
+       isl_dim_map_range(dim_map, src->start + 1, 2, 1, 1, src->nparam, 1);
+       isl_dim_map_range(dim_map, src->start + 2, 2, 1, 1, src->nparam, -1);
+       isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 1, 2,
+                         isl_dim_size(dim, isl_dim_set), 1,
+                         src->nvar, 1);
+       isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 2, 2,
+                         isl_dim_size(dim, isl_dim_set), 1,
+                         src->nvar, -1);
+
+       graph->lp = isl_basic_set_extend_constraints(graph->lp,
+                       coef->n_eq, coef->n_ineq);
+       graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+                                                          coef, dim_map);
+       isl_dim_free(dim);
+
+       return 0;
+}
+
+/* Add constraints to graph->lp that force all dependence
+ * to be respected and attempt to carry it.
+ */
+static int add_all_constraints(struct isl_sched_graph *graph)
+{
+       int i;
+
+       for (i = 0; i < graph->n_edge; ++i) {
+               struct isl_sched_edge *edge= &graph->edge[i];
+               if (edge->src == edge->dst &&
+                   add_intra_constraints(graph, i) < 0)
+                       return -1;
+               if (edge->src != edge->dst &&
+                   add_inter_constraints(graph, i) < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+/* Construct an LP problem for finding schedule coefficients
+ * such that the schedule carries as many dependences as possible.
+ * In particular, for each dependence i, we bound the dependence distance
+ * from below by e_i, with 0 <= e_i <= 1 and then maximize the sum
+ * of all e_i's.  Dependence with e_i = 0 in the solution are simply
+ * respected, while those with e_i > 0 (in practice e_i = 1) are carried.
+ *
+ * All variables of the LP are non-negative.  The actual coefficients
+ * may be negative, so each coefficient is represented as the difference
+ * of two non-negative variables.  The negative part always appears
+ * immediately before the positive part.
+ * Other than that, the variables have the following order
+ *
+ *     - sum of (1 - e_i) over all edges
+ *     - sum of positive and negative parts of all c_n coefficients
+ *             (unconstrained when computing non-parametric schedules)
+ *     - sum of positive and negative parts of all c_x coefficients
+ *     - for each edge
+ *             - e_i
+ *     - for each node
+ *             - c_i_0
+ *             - positive and negative parts of c_i_n (if parametric)
+ *             - positive and negative parts of c_i_x
+ *
+ * The constraints are those from the edges plus three equalities
+ * to express the sums and n_edge inequalities to express e_i <= 1.
+ */
+static int setup_carry_lp(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+       int i, j;
+       int k;
+       isl_dim *dim;
+       unsigned total;
+       int n_eq, n_ineq;
+
+       total = 3 + graph->n_edge;
+       for (i = 0; i < graph->n; ++i) {
+               struct isl_sched_node *node = &graph->node[graph->sorted[i]];
+               node->start = total;
+               total += 1 + 2 * (node->nparam + node->nvar);
+       }
+
+       if (count_constraints(graph, &n_eq, &n_ineq, 1) < 0)
+               return -1;
+
+       dim = isl_dim_set_alloc(ctx, 0, total);
+       isl_basic_set_free(graph->lp);
+       n_eq += 3;
+       n_ineq += graph->n_edge;
+       graph->lp = isl_basic_set_alloc_dim(dim, 0, n_eq, n_ineq);
+       graph->lp = isl_basic_set_set_rational(graph->lp);
+
+       k = isl_basic_set_alloc_equality(graph->lp);
+       if (k < 0)
+               return -1;
+       isl_seq_clr(graph->lp->eq[k], 1 +  total);
+       isl_int_set_si(graph->lp->eq[k][0], -graph->n_edge);
+       isl_int_set_si(graph->lp->eq[k][1], 1);
+       for (i = 0; i < graph->n_edge; ++i)
+               isl_int_set_si(graph->lp->eq[k][4 + i], 1);
+
+       k = isl_basic_set_alloc_equality(graph->lp);
+       if (k < 0)
+               return -1;
+       isl_seq_clr(graph->lp->eq[k], 1 +  total);
+       isl_int_set_si(graph->lp->eq[k][2], -1);
+       for (i = 0; i < graph->n; ++i) {
+               int pos = 1 + graph->node[i].start + 1;
+
+               for (j = 0; j < 2 * graph->node[i].nparam; ++j)
+                       isl_int_set_si(graph->lp->eq[k][pos + j], 1);
+       }
+
+       k = isl_basic_set_alloc_equality(graph->lp);
+       if (k < 0)
+               return -1;
+       isl_seq_clr(graph->lp->eq[k], 1 +  total);
+       isl_int_set_si(graph->lp->eq[k][3], -1);
+       for (i = 0; i < graph->n; ++i) {
+               struct isl_sched_node *node = &graph->node[i];
+               int pos = 1 + node->start + 1 + 2 * node->nparam;
+
+               for (j = 0; j < 2 * node->nvar; ++j)
+                       isl_int_set_si(graph->lp->eq[k][pos + j], 1);
+       }
+
+       for (i = 0; i < graph->n_edge; ++i) {
+               k = isl_basic_set_alloc_inequality(graph->lp);
+               if (k < 0)
+                       return -1;
+               isl_seq_clr(graph->lp->ineq[k], 1 +  total);
+               isl_int_set_si(graph->lp->ineq[k][4 + i], -1);
+               isl_int_set_si(graph->lp->ineq[k][0], 1);
+       }
+
+       if (add_all_constraints(graph) < 0)
+               return -1;
+
+       return 0;
+}
+
+/* Construct a schedule row for each node such that as many dependences
+ * as possible are carried and then continue with the next band.
+ */
+static int carry_dependences(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+       isl_vec *sol;
+       isl_basic_set *lp;
+
+       if (setup_carry_lp(ctx, graph) < 0)
+               return -1;
+
+       lp = isl_basic_set_copy(graph->lp);
+       sol = isl_tab_basic_set_non_neg_lexmin(lp);
+       if (!sol)
+               return -1;
+
+       if (sol->size == 0) {
+               isl_vec_free(sol);
+               isl_die(ctx, isl_error_internal,
+                       "error in schedule construction", return -1);
+       }
+
+       if (isl_int_cmp_si(sol->el[1], graph->n_edge) >= 0) {
+               isl_vec_free(sol);
+               isl_die(ctx, isl_error_unknown,
+                       "unable to carry dependences", return -1);
+       }
+
+       if (update_schedule(graph, sol, 0) < 0)
+               return -1;
+
+       return compute_next_band(ctx, graph);
+}
+
+/* Compute a schedule for a connected dependence graph.
+ * We try to find a sequence of as many schedule rows as possible that result
+ * in non-negative dependence distances (independent of the previous rows
+ * in the sequence, i.e., such that the sequence is tilable).
+ * If we can't find any more rows we either
+ * - split between SCCs and start over (assuming we found an interesting
+ *     pair of SCCs between which to split)
+ * - continue with the next band (assuming the current band has at least
+ *     one row)
+ * - try to carry as many dependences as possible and continue with the next
+ *     band
+ *
+ * If we manage to complete the schedule, we finish off by topologically
+ * sorting the statements based on the remaining dependences.
+ */
+static int compute_schedule_wcc(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+       if (detect_sccs(graph) < 0)
+               return -1;
+       sort_sccs(graph);
+
+       if (compute_maxvar(graph) < 0)
+               return -1;
+
+       while (graph->n_row < graph->maxvar) {
+               isl_vec *sol;
+
+               graph->src_scc = -1;
+               graph->dst_scc = -1;
+
+               if (setup_lp(ctx, graph) < 0)
+                       return -1;
+               sol = solve_lp(graph);
+               if (!sol)
+                       return -1;
+               if (sol->size == 0) {
+                       isl_vec_free(sol);
+                       if (graph->src_scc >= 0)
+                               return compute_split_schedule(ctx, graph);
+                       if (graph->n_total_row > graph->band_start)
+                               return compute_next_band(ctx, graph);
+                       return carry_dependences(ctx, graph);
+               }
+               if (update_schedule(graph, sol, 1) < 0)
+                       return -1;
+       }
+
+       if (graph->n_total_row > graph->band_start)
+               next_band(graph);
+       return sort_statements(ctx, graph);
+}
+
+/* Compute a schedule for each component (identified by node->scc)
+ * of the dependence graph separately and then combine the results.
+ */
+static int compute_component_schedule(isl_ctx *ctx,
+       struct isl_sched_graph *graph)
+{
+       int wcc, i;
+       int n, n_edge;
+       int n_total_row, orig_total_row;
+       int n_band, orig_band;
+
+       n_total_row = 0;
+       orig_total_row = graph->n_total_row;
+       n_band = 0;
+       orig_band = graph->n_band;
+       for (wcc = 0; wcc < graph->scc; ++wcc) {
+               n = 0;
+               for (i = 0; i < graph->n; ++i)
+                       if (graph->node[i].scc == wcc)
+                               n++;
+               n_edge = 0;
+               for (i = 0; i < graph->n_edge; ++i)
+                       if (graph->edge[i].src->scc == wcc)
+                               n_edge++;
+
+               if (compute_sub_schedule(ctx, graph, n, n_edge,
+                                   &node_scc_exactly,
+                                   &edge_src_scc_exactly, wcc, 1) < 0)
+                       return -1;
+               if (graph->n_total_row > n_total_row)
+                       n_total_row = graph->n_total_row;
+               graph->n_total_row = orig_total_row;
+               if (graph->n_band > n_band)
+                       n_band = graph->n_band;
+               graph->n_band = orig_band;
+       }
+
+       graph->n_total_row = n_total_row;
+       graph->n_band = n_band;
+
+       return pad_schedule(graph);
+}
+
+/* Compute a schedule for the given dependence graph.
+ * We first check if the graph is connected (through validity dependences)
+ * and if so compute a schedule for each component separately.
+ */
+static int compute_schedule(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+       if (detect_wccs(graph) < 0)
+               return -1;
+
+       if (graph->scc > 1)
+               return compute_component_schedule(ctx, graph);
+
+       return compute_schedule_wcc(ctx, graph);
+}
+
+/* Compute a schedule for the given union of domains that respects
+ * all the validity dependences and tries to minimize the dependence
+ * distances over the proximity dependences.
+ */
+__isl_give isl_schedule *isl_union_set_compute_schedule(
+       __isl_take isl_union_set *domain,
+       __isl_take isl_union_map *validity,
+       __isl_take isl_union_map *proximity)
+{
+       isl_ctx *ctx = isl_union_set_get_ctx(domain);
+       isl_dim *dim;
+       struct isl_sched_graph graph = { 0 };
+       isl_schedule *sched;
+
+       domain = isl_union_set_align_params(domain,
+                                           isl_union_map_get_dim(validity));
+       domain = isl_union_set_align_params(domain,
+                                           isl_union_map_get_dim(proximity));
+       dim = isl_union_set_get_dim(domain);
+       validity = isl_union_map_align_params(validity, isl_dim_copy(dim));
+       proximity = isl_union_map_align_params(proximity, dim);
+
+       if (!domain)
+               goto error;
+
+       graph.n = isl_union_set_n_set(domain);
+       if (graph.n == 0)
+               goto empty;
+       if (graph_alloc(ctx, &graph, graph.n,
+           isl_union_map_n_map(validity) + isl_union_map_n_map(proximity)) < 0)
+               goto error;
+       graph.root = 1;
+       graph.n = 0;
+       if (isl_union_set_foreach_set(domain, &extract_node, &graph) < 0)
+               goto error;
+       if (graph_init_table(ctx, &graph) < 0)
+               goto error;
+       graph.n_edge = 0;
+       if (isl_union_map_foreach_map(validity, &extract_edge, &graph) < 0)
+               goto error;
+       if (graph_init_edge_table(ctx, &graph) < 0)
+               goto error;
+       if (isl_union_map_foreach_map(proximity, &extract_edge, &graph) < 0)
+               goto error;
+
+       if (compute_schedule(ctx, &graph) < 0)
+               goto error;
+
+empty:
+       sched = extract_schedule(&graph, isl_union_set_get_dim(domain));
+
+       graph_free(ctx, &graph);
+       isl_union_set_free(domain);
+       isl_union_map_free(validity);
+       isl_union_map_free(proximity);
+
+       return sched;
+error:
+       graph_free(ctx, &graph);
+       isl_union_set_free(domain);
+       isl_union_map_free(validity);
+       isl_union_map_free(proximity);
+       return NULL;
+}
+
+void *isl_schedule_free(__isl_take isl_schedule *sched)
+{
+       int i;
+       if (!sched)
+               return NULL;
+       for (i = 0; i < sched->n; ++i) {
+               isl_map_free(sched->node[i].sched);
+               free(sched->node[i].band_end);
+       }
+       isl_dim_free(sched->dim);
+       free(sched);
+       return NULL;
+}
+
+__isl_give isl_union_map *isl_schedule_get_map(__isl_keep isl_schedule *sched)
+{
+       int i;
+       isl_union_map *umap;
+
+       if (!sched)
+               return NULL;
+
+       umap = isl_union_map_empty(isl_dim_copy(sched->dim));
+       for (i = 0; i < sched->n; ++i)
+               umap = isl_union_map_add_map(umap,
+                                           isl_map_copy(sched->node[i].sched));
+
+       return umap;
+}
+
+int isl_schedule_n_band(__isl_keep isl_schedule *sched)
+{
+       return sched ? sched->n_band : 0;
+}
+
+/* Construct a mapping that maps each domain to the band in its schedule
+ * with the specified band index.  Note that bands with the same index
+ * but for different domains do not need to be related.
+ */
+__isl_give isl_union_map *isl_schedule_get_band(__isl_keep isl_schedule *sched,
+       unsigned band)
+{
+       int i;
+       isl_union_map *umap;
+
+       if (!sched)
+               return NULL;
+
+       umap = isl_union_map_empty(isl_dim_copy(sched->dim));
+       for (i = 0; i < sched->n; ++i) {
+               int start, end;
+               isl_map *map;
+
+               if (band >= sched->node[i].n_band)
+                       continue;
+
+               start = band > 0 ? sched->node[i].band_end[band - 1] : 0;
+               end = sched->node[i].band_end[band];
+
+               map = isl_map_copy(sched->node[i].sched);
+
+               map = isl_map_project_out(map, isl_dim_out, end,
+                                         sched->n_total_row - end);
+               map = isl_map_project_out(map, isl_dim_out, 0, start);
+
+               umap = isl_union_map_add_map(umap, map);
+       }
+
+       return umap;
+}
index 28af80e..630d2fe 100644 (file)
--- a/isl_tab.c
+++ b/isl_tab.c
@@ -3250,7 +3250,8 @@ __isl_keep isl_basic_set *isl_tab_peek_bset(struct isl_tab *tab)
        return (isl_basic_set *)tab->bmap;
 }
 
-void isl_tab_dump(struct isl_tab *tab, FILE *out, int indent)
+static void isl_tab_print_internal(__isl_keep struct isl_tab *tab,
+       FILE *out, int indent)
 {
        unsigned r, c;
        int i;
@@ -3319,9 +3320,14 @@ void isl_tab_dump(struct isl_tab *tab, FILE *out, int indent)
        tab->mat->n_row = tab->n_row;
        c = tab->mat->n_col;
        tab->mat->n_col = 2 + tab->M + tab->n_col;
-       isl_mat_dump(tab->mat, out, indent);
+       isl_mat_print_internal(tab->mat, out, indent);
        tab->mat->n_row = r;
        tab->mat->n_col = c;
        if (tab->bmap)
                isl_basic_map_print_internal(tab->bmap, out, indent);
 }
+
+void isl_tab_dump(__isl_keep struct isl_tab *tab)
+{
+       isl_tab_print_internal(tab, stderr, 0);
+}
index 51a0afc..6888044 100644 (file)
--- a/isl_tab.h
+++ b/isl_tab.h
@@ -161,6 +161,9 @@ struct isl_tab {
        int n_unbounded;
        struct isl_mat *basis;
 
+       int (*conflict)(int con, void *user);
+       void *conflict_user;
+
        unsigned strict_redundant : 1;
        unsigned need_undo : 1;
        unsigned rational : 1;
@@ -224,12 +227,27 @@ int isl_tab_rollback(struct isl_tab *tab, struct isl_tab_undo *snap) WARN_UNUSED
 struct isl_tab *isl_tab_relax(struct isl_tab *tab, int con) WARN_UNUSED;
 int isl_tab_select_facet(struct isl_tab *tab, int con) WARN_UNUSED;
 
-void isl_tab_dump(struct isl_tab *tab, FILE *out, int indent);
+void isl_tab_dump(__isl_keep struct isl_tab *tab);
 
 struct isl_map *isl_tab_basic_map_partial_lexopt(
                struct isl_basic_map *bmap, struct isl_basic_set *dom,
                struct isl_set **empty, int max);
 
+/* An isl_region represents a sequence of consecutive variables.
+ * pos is the location (starting at 0) of the first variable in the sequence.
+ */
+struct isl_region {
+       int pos;
+       int len;
+};
+
+__isl_give isl_vec *isl_tab_basic_set_non_trivial_lexmin(
+       __isl_take isl_basic_set *bset, int n_op, int n_region,
+       struct isl_region *region,
+       int (*conflict)(int con, void *user), void *user);
+__isl_give isl_vec *isl_tab_basic_set_non_neg_lexmin(
+       __isl_take isl_basic_set *bset);
+
 /* private */
 
 struct isl_tab_var *isl_tab_var_from_row(struct isl_tab *tab, int i);
index 56eb161..62b4cd1 100644 (file)
@@ -26,7 +26,7 @@
  * The strategy used for obtaining a feasible solution is different
  * from the one used in isl_tab.c.  In particular, in isl_tab.c,
  * upon finding a constraint that is not yet satisfied, we pivot
- * in a row that increases the constant term of row holding the
+ * in a row that increases the constant term of the row holding the
  * constraint, making sure the sample solution remains feasible
  * for all the constraints it already satisfied.
  * Here, we always pivot in the row holding the constraint,
@@ -1113,37 +1113,116 @@ static int first_neg(struct isl_tab *tab)
        return -1;
 }
 
+/* Check whether the invariant that all columns are lexico-positive
+ * is satisfied.  This function is not called from the current code
+ * but is useful during debugging.
+ */
+static void check_lexpos(struct isl_tab *tab)
+{
+       unsigned off = 2 + tab->M;
+       int col;
+       int var;
+       int row;
+
+       for (col = tab->n_dead; col < tab->n_col; ++col) {
+               if (tab->col_var[col] >= 0 &&
+                   (tab->col_var[col] < tab->n_param ||
+                    tab->col_var[col] >= tab->n_var - tab->n_div))
+                       continue;
+               for (var = tab->n_param; var < tab->n_var - tab->n_div; ++var) {
+                       if (!tab->var[var].is_row) {
+                               if (tab->var[var].index == col)
+                                       break;
+                               else
+                                       continue;
+                       }
+                       row = tab->var[var].index;
+                       if (isl_int_is_zero(tab->mat->row[row][off + col]))
+                               continue;
+                       if (isl_int_is_pos(tab->mat->row[row][off + col]))
+                               break;
+                       fprintf(stderr, "lexneg column %d (row %d)\n",
+                               col, row);
+               }
+               if (var >= tab->n_var - tab->n_div)
+                       fprintf(stderr, "zero column %d\n", col);
+       }
+}
+
+/* Report to the caller that the given constraint is part of an encountered
+ * conflict.
+ */
+static int report_conflicting_constraint(struct isl_tab *tab, int con)
+{
+       return tab->conflict(con, tab->conflict_user);
+}
+
+/* Given a conflicting row in the tableau, report all constraints
+ * involved in the row to the caller.  That is, the row itself
+ * (if represents a constraint) and all constraint columns with
+ * non-zero (and therefore negative) coefficient.
+ */
+static int report_conflict(struct isl_tab *tab, int row)
+{
+       int j;
+       isl_int *tr;
+
+       if (!tab->conflict)
+               return 0;
+
+       if (tab->row_var[row] < 0 &&
+           report_conflicting_constraint(tab, ~tab->row_var[row]) < 0)
+               return -1;
+
+       tr = tab->mat->row[row] + 2 + tab->M;
+
+       for (j = tab->n_dead; j < tab->n_col; ++j) {
+               if (tab->col_var[j] >= 0 &&
+                   (tab->col_var[j] < tab->n_param  ||
+                   tab->col_var[j] >= tab->n_var - tab->n_div))
+                       continue;
+
+               if (!isl_int_is_neg(tr[j]))
+                       continue;
+
+               if (tab->col_var[j] < 0 &&
+                   report_conflicting_constraint(tab, ~tab->col_var[j]) < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
 /* Resolve all known or obviously violated constraints through pivoting.
  * In particular, as long as we can find any violated constraint, we
  * look for a pivoting column that would result in the lexicographically
  * smallest increment in the sample point.  If there is no such column
  * then the tableau is infeasible.
  */
-static struct isl_tab *restore_lexmin(struct isl_tab *tab) WARN_UNUSED;
-static struct isl_tab *restore_lexmin(struct isl_tab *tab)
+static int restore_lexmin(struct isl_tab *tab) WARN_UNUSED;
+static int restore_lexmin(struct isl_tab *tab)
 {
        int row, col;
 
        if (!tab)
-               return NULL;
+               return -1;
        if (tab->empty)
-               return tab;
+               return 0;
        while ((row = first_neg(tab)) != -1) {
                col = lexmin_pivot_col(tab, row);
                if (col >= tab->n_col) {
+                       if (report_conflict(tab, row) < 0)
+                               return -1;
                        if (isl_tab_mark_empty(tab) < 0)
-                               goto error;
-                       return tab;
+                               return -1;
+                       return 0;
                }
                if (col < 0)
-                       goto error;
+                       return -1;
                if (isl_tab_pivot(tab, row, col) < 0)
-                       goto error;
+                       return -1;
        }
-       return tab;
-error:
-       isl_tab_free(tab);
-       return NULL;
+       return 0;
 }
 
 /* Given a row that represents an equality, look for an appropriate
@@ -1254,78 +1333,77 @@ static int is_constant(struct isl_tab *tab, int row)
  * In the end we try to use one of the two constraints to eliminate
  * a column.
  */
-static struct isl_tab *add_lexmin_eq(struct isl_tab *tab, isl_int *eq) WARN_UNUSED;
-static struct isl_tab *add_lexmin_eq(struct isl_tab *tab, isl_int *eq)
+static int add_lexmin_eq(struct isl_tab *tab, isl_int *eq) WARN_UNUSED;
+static int add_lexmin_eq(struct isl_tab *tab, isl_int *eq)
 {
        int r1, r2;
        int row;
        struct isl_tab_undo *snap;
 
        if (!tab)
-               return NULL;
+               return -1;
        snap = isl_tab_snap(tab);
        r1 = isl_tab_add_row(tab, eq);
        if (r1 < 0)
-               goto error;
+               return -1;
        tab->con[r1].is_nonneg = 1;
        if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r1]) < 0)
-               goto error;
+               return -1;
 
        row = tab->con[r1].index;
        if (is_constant(tab, row)) {
                if (!isl_int_is_zero(tab->mat->row[row][1]) ||
                    (tab->M && !isl_int_is_zero(tab->mat->row[row][2]))) {
                        if (isl_tab_mark_empty(tab) < 0)
-                               goto error;
-                       return tab;
+                               return -1;
+                       return 0;
                }
                if (isl_tab_rollback(tab, snap) < 0)
-                       goto error;
-               return tab;
+                       return -1;
+               return 0;
        }
 
-       tab = restore_lexmin(tab);
-       if (!tab || tab->empty)
-               return tab;
+       if (restore_lexmin(tab) < 0)
+               return -1;
+       if (tab->empty)
+               return 0;
 
        isl_seq_neg(eq, eq, 1 + tab->n_var);
 
        r2 = isl_tab_add_row(tab, eq);
        if (r2 < 0)
-               goto error;
+               return -1;
        tab->con[r2].is_nonneg = 1;
        if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r2]) < 0)
-               goto error;
+               return -1;
 
-       tab = restore_lexmin(tab);
-       if (!tab || tab->empty)
-               return tab;
+       if (restore_lexmin(tab) < 0)
+               return -1;
+       if (tab->empty)
+               return 0;
 
        if (!tab->con[r1].is_row) {
                if (isl_tab_kill_col(tab, tab->con[r1].index) < 0)
-                       goto error;
+                       return -1;
        } else if (!tab->con[r2].is_row) {
                if (isl_tab_kill_col(tab, tab->con[r2].index) < 0)
-                       goto error;
+                       return -1;
        }
 
        if (tab->bmap) {
                tab->bmap = isl_basic_map_add_ineq(tab->bmap, eq);
                if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0)
-                       goto error;
+                       return -1;
                isl_seq_neg(eq, eq, 1 + tab->n_var);
                tab->bmap = isl_basic_map_add_ineq(tab->bmap, eq);
                isl_seq_neg(eq, eq, 1 + tab->n_var);
                if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0)
-                       goto error;
+                       return -1;
                if (!tab->bmap)
-                       goto error;
+                       return -1;
        }
 
-       return tab;
-error:
-       isl_tab_free(tab);
-       return NULL;
+       return 0;
 }
 
 /* Add an inequality to the tableau, resolving violations using
@@ -1356,8 +1434,9 @@ static struct isl_tab *add_lexmin_ineq(struct isl_tab *tab, isl_int *ineq)
                return tab;
        }
 
-       tab = restore_lexmin(tab);
-       if (tab && !tab->empty && tab->con[r].is_row &&
+       if (restore_lexmin(tab) < 0)
+               goto error;
+       if (!tab->empty && tab->con[r].is_row &&
                 isl_tab_row_is_redundant(tab, tab->con[r].index))
                if (isl_tab_mark_redundant(tab, tab->con[r].index) < 0)
                        goto error;
@@ -1568,8 +1647,9 @@ static struct isl_tab *cut_to_integer_lexmin(struct isl_tab *tab)
                        if (row < 0)
                                goto error;
                } while ((var = next_non_integer_var(tab, var, &flags)) != -1);
-               tab = restore_lexmin(tab);
-               if (!tab || tab->empty)
+               if (restore_lexmin(tab) < 0)
+                       goto error;
+               if (tab->empty)
                        break;
        }
        return tab;
@@ -1981,8 +2061,8 @@ static struct isl_tab *tab_for_lexmin(struct isl_basic_map *bmap,
                if (!tab || tab->empty)
                        return tab;
        }
-       if (bmap->n_eq)
-               tab = restore_lexmin(tab);
+       if (bmap->n_eq && restore_lexmin(tab) < 0)
+               goto error;
        for (i = 0; i < bmap->n_ineq; ++i) {
                if (max)
                        isl_seq_neg(bmap->ineq[i] + 1 + tab->n_param,
@@ -2119,7 +2199,8 @@ static void context_lex_add_eq(struct isl_context *context, isl_int *eq,
        struct isl_context_lex *clex = (struct isl_context_lex *)context;
        if (isl_tab_extend_cons(clex->tab, 2) < 0)
                goto error;
-       clex->tab = add_lexmin_eq(clex->tab, eq);
+       if (add_lexmin_eq(clex->tab, eq) < 0)
+               goto error;
        if (check) {
                int v = tab_has_valid_sample(clex->tab, eq, 1);
                if (v < 0)
@@ -2478,7 +2559,8 @@ static struct isl_context *isl_context_lex_alloc(struct isl_basic_set *dom)
        clex->context.op = &isl_context_lex_op;
 
        clex->tab = context_tab_for_lexmin(isl_basic_set_copy(dom));
-       clex->tab = restore_lexmin(clex->tab);
+       if (restore_lexmin(clex->tab) < 0)
+               goto error;
        clex->tab = check_integer_feasible(clex->tab);
        if (!clex->tab)
                goto error;
@@ -2958,7 +3040,8 @@ static void propagate_equalities(struct isl_context_gbr *cgbr,
                if (isl_tab_kill_col(tab, j) < 0)
                        goto error;
 
-               tab = restore_lexmin(tab);
+               if (restore_lexmin(tab) < 0)
+                       goto error;
        }
 
        isl_vec_free(eq);
@@ -3604,6 +3687,7 @@ error:
 static void find_solutions(struct isl_sol *sol, struct isl_tab *tab)
 {
        struct isl_context *context;
+       int r;
 
        if (!tab || sol->error)
                goto error;
@@ -3615,7 +3699,7 @@ static void find_solutions(struct isl_sol *sol, struct isl_tab *tab)
        if (context->op->is_empty(context))
                goto done;
 
-       for (; tab && !tab->empty; tab = restore_lexmin(tab)) {
+       for (r = 0; r >= 0 && tab && !tab->empty; r = restore_lexmin(tab)) {
                int flags;
                int row;
                enum isl_tab_row_sign sgn;
@@ -3709,6 +3793,8 @@ static void find_solutions(struct isl_sol *sol, struct isl_tab *tab)
                if (row < 0)
                        goto error;
        }
+       if (r < 0)
+               goto error;
 done:
        sol_add(sol, tab);
        isl_tab_free(tab);
@@ -3899,9 +3985,9 @@ static __isl_give isl_map *basic_map_partial_lexopt_base(
                goto error;
 
        context = sol_map->sol.context;
-       if (isl_basic_set_fast_is_empty(context->op->peek_basic_set(context)))
+       if (isl_basic_set_plain_is_empty(context->op->peek_basic_set(context)))
                /* nothing */;
-       else if (isl_basic_map_fast_is_empty(bmap))
+       else if (isl_basic_map_plain_is_empty(bmap))
                sol_map_add_empty_if_needed(sol_map,
                    isl_basic_set_copy(context->op->peek_basic_set(context)));
        else {
@@ -4420,6 +4506,9 @@ struct isl_map *isl_tab_basic_map_partial_lexopt(
        isl_assert(bmap->ctx,
            isl_basic_map_compatible_domain(bmap, dom), goto error);
 
+       if (isl_basic_set_dim(dom, isl_dim_all) == 0)
+               return basic_map_partial_lexopt(bmap, dom, empty, max);
+
        bmap = isl_basic_map_intersect_domain(bmap, isl_basic_set_copy(dom));
        bmap = isl_basic_map_detect_equalities(bmap);
        bmap = isl_basic_map_remove_redundancies(bmap);
@@ -4549,7 +4638,7 @@ int isl_basic_map_foreach_lexopt(__isl_keep isl_basic_map *bmap, int max,
        bmap = isl_basic_map_detect_equalities(bmap);
        sol_for = sol_for_init(bmap, max, fn, user);
 
-       if (isl_basic_map_fast_is_empty(bmap))
+       if (isl_basic_map_plain_is_empty(bmap))
                /* nothing */;
        else {
                struct isl_tab *tab;
@@ -4586,3 +4675,309 @@ int isl_basic_map_foreach_lexmax(__isl_keep isl_basic_map *bmap,
 {
        return isl_basic_map_foreach_lexopt(bmap, 1, fn, user);
 }
+
+/* Check if the given sequence of len variables starting at pos
+ * represents a trivial (i.e., zero) solution.
+ * The variables are assumed to be non-negative and to come in pairs,
+ * with each pair representing a variable of unrestricted sign.
+ * The solution is trivial if each such pair in the sequence consists
+ * of two identical values, meaning that the variable being represented
+ * has value zero.
+ */
+static int region_is_trivial(struct isl_tab *tab, int pos, int len)
+{
+       int i;
+
+       if (len == 0)
+               return 0;
+
+       for (i = 0; i < len; i +=  2) {
+               int neg_row;
+               int pos_row;
+
+               neg_row = tab->var[pos + i].is_row ?
+                               tab->var[pos + i].index : -1;
+               pos_row = tab->var[pos + i + 1].is_row ?
+                               tab->var[pos + i + 1].index : -1;
+
+               if ((neg_row < 0 ||
+                    isl_int_is_zero(tab->mat->row[neg_row][1])) &&
+                   (pos_row < 0 ||
+                    isl_int_is_zero(tab->mat->row[pos_row][1])))
+                       continue;
+
+               if (neg_row < 0 || pos_row < 0)
+                       return 0;
+               if (isl_int_ne(tab->mat->row[neg_row][1],
+                              tab->mat->row[pos_row][1]))
+                       return 0;
+       }
+
+       return 1;
+}
+
+/* Return the index of the first trivial region or -1 if all regions
+ * are non-trivial.
+ */
+static int first_trivial_region(struct isl_tab *tab,
+       int n_region, struct isl_region *region)
+{
+       int i;
+
+       for (i = 0; i < n_region; ++i) {
+               if (region_is_trivial(tab, region[i].pos, region[i].len))
+                       return i;
+       }
+
+       return -1;
+}
+
+/* Check if the solution is optimal, i.e., whether the first
+ * n_op entries are zero.
+ */
+static int is_optimal(__isl_keep isl_vec *sol, int n_op)
+{
+       int i;
+
+       for (i = 0; i < n_op; ++i)
+               if (!isl_int_is_zero(sol->el[1 + i]))
+                       return 0;
+       return 1;
+}
+
+/* Add constraints to "tab" that ensure that any solution is significantly
+ * better that that represented by "sol".  That is, find the first
+ * relevant (within first n_op) non-zero coefficient and force it (along
+ * with all previous coefficients) to be zero.
+ * If the solution is already optimal (all relevant coefficients are zero),
+ * then just mark the table as empty.
+ */
+static int force_better_solution(struct isl_tab *tab,
+       __isl_keep isl_vec *sol, int n_op)
+{
+       int i;
+       isl_ctx *ctx;
+       isl_vec *v = NULL;
+
+       if (!sol)
+               return -1;
+
+       for (i = 0; i < n_op; ++i)
+               if (!isl_int_is_zero(sol->el[1 + i]))
+                       break;
+
+       if (i == n_op) {
+               if (isl_tab_mark_empty(tab) < 0)
+                       return -1;
+               return 0;
+       }
+
+       ctx = isl_vec_get_ctx(sol);
+       v = isl_vec_alloc(ctx, 1 + tab->n_var);
+       if (!v)
+               return -1;
+
+       for (; i >= 0; --i) {
+               v = isl_vec_clr(v);
+               isl_int_set_si(v->el[1 + i], -1);
+               if (add_lexmin_eq(tab, v->el) < 0)
+                       goto error;
+       }
+
+       isl_vec_free(v);
+       return 0;
+error:
+       isl_vec_free(v);
+       return -1;
+}
+
+struct isl_trivial {
+       int update;
+       int region;
+       int side;
+       struct isl_tab_undo *snap;
+};
+
+/* Return the lexicographically smallest non-trivial solution of the
+ * given ILP problem.
+ *
+ * All variables are assumed to be non-negative.
+ *
+ * n_op is the number of initial coordinates to optimize.
+ * That is, once a solution has been found, we will only continue looking
+ * for solution that result in significantly better values for those
+ * initial coordinates.  That is, we only continue looking for solutions
+ * that increase the number of initial zeros in this sequence.
+ *
+ * A solution is non-trivial, if it is non-trivial on each of the
+ * specified regions.  Each region represents a sequence of pairs
+ * of variables.  A solution is non-trivial on such a region if
+ * at least one of these pairs consists of different values, i.e.,
+ * such that the non-negative variable represented by the pair is non-zero.
+ *
+ * Whenever a conflict is encountered, all constraints involved are
+ * reported to the caller through a call to "conflict".
+ *
+ * We perform a simple branch-and-bound backtracking search.
+ * Each level in the search represents initially trivial region that is forced
+ * to be non-trivial.
+ * At each level we consider n cases, where n is the length of the region.
+ * In terms of the n/2 variables of unrestricted signs being encoded by
+ * the region, we consider the cases
+ *     x_0 >= 1
+ *     x_0 <= -1
+ *     x_0 = 0 and x_1 >= 1
+ *     x_0 = 0 and x_1 <= -1
+ *     x_0 = 0 and x_1 = 0 and x_2 >= 1
+ *     x_0 = 0 and x_1 = 0 and x_2 <= -1
+ *     ...
+ * The cases are considered in this order, assuming that each pair
+ * x_i_a x_i_b represents the value x_i_b - x_i_a.
+ * That is, x_0 >= 1 is enforced by adding the constraint
+ *     x_0_b - x_0_a >= 1
+ */
+__isl_give isl_vec *isl_tab_basic_set_non_trivial_lexmin(
+       __isl_take isl_basic_set *bset, int n_op, int n_region,
+       struct isl_region *region,
+       int (*conflict)(int con, void *user), void *user)
+{
+       int i, j;
+       int need_update = 0;
+       int r;
+       isl_ctx *ctx = isl_basic_set_get_ctx(bset);
+       isl_vec *v = NULL;
+       isl_vec *sol = isl_vec_alloc(ctx, 0);
+       struct isl_tab *tab;
+       struct isl_trivial *triv = NULL;
+       int level, init;
+
+       tab = tab_for_lexmin(isl_basic_map_from_range(bset), NULL, 0, 0);
+       if (!tab)
+               goto error;
+       tab->conflict = conflict;
+       tab->conflict_user = user;
+
+       v = isl_vec_alloc(ctx, 1 + tab->n_var);
+       triv = isl_calloc_array(ctx, struct isl_trivial, n_region);
+       if (!v || !triv)
+               goto error;
+
+       level = 0;
+       init = 1;
+
+       while (level >= 0) {
+               int side, base;
+
+               if (init) {
+                       tab = cut_to_integer_lexmin(tab);
+                       if (!tab)
+                               goto error;
+                       if (tab->empty)
+                               goto backtrack;
+                       r = first_trivial_region(tab, n_region, region);
+                       if (r < 0) {
+                               for (i = 0; i < level; ++i)
+                                       triv[i].update = 1;
+                               isl_vec_free(sol);
+                               sol = isl_tab_get_sample_value(tab);
+                               if (!sol)
+                                       goto error;
+                               if (is_optimal(sol, n_op))
+                                       break;
+                               goto backtrack;
+                       }
+                       if (level >= n_region)
+                               isl_die(ctx, isl_error_internal,
+                                       "nesting level too deep", goto error);
+                       if (isl_tab_extend_cons(tab,
+                                           2 * region[r].len + 2 * n_op) < 0)
+                               goto error;
+                       triv[level].region = r;
+                       triv[level].side = 0;
+               }
+
+               r = triv[level].region;
+               side = triv[level].side;
+               base = 2 * (side/2);
+
+               if (side >= region[r].len) {
+backtrack:
+                       level--;
+                       init = 0;
+                       if (level >= 0)
+                               if (isl_tab_rollback(tab, triv[level].snap) < 0)
+                                       goto error;
+                       continue;
+               }
+
+               if (triv[level].update) {
+                       if (force_better_solution(tab, sol, n_op) < 0)
+                               goto error;
+                       triv[level].update = 0;
+               }
+
+               if (side == base && base >= 2) {
+                       for (j = base - 2; j < base; ++j) {
+                               v = isl_vec_clr(v);
+                               isl_int_set_si(v->el[1 + region[r].pos + j], 1);
+                               if (add_lexmin_eq(tab, v->el) < 0)
+                                       goto error;
+                       }
+               }
+
+               triv[level].snap = isl_tab_snap(tab);
+               if (isl_tab_push_basis(tab) < 0)
+                       goto error;
+
+               v = isl_vec_clr(v);
+               isl_int_set_si(v->el[0], -1);
+               isl_int_set_si(v->el[1 + region[r].pos + side], -1);
+               isl_int_set_si(v->el[1 + region[r].pos + (side ^ 1)], 1);
+               tab = add_lexmin_ineq(tab, v->el);
+
+               triv[level].side++;
+               level++;
+               init = 1;
+       }
+
+       free(triv);
+       isl_vec_free(v);
+       isl_tab_free(tab);
+       isl_basic_set_free(bset);
+
+       return sol;
+error:
+       free(triv);
+       isl_vec_free(v);
+       isl_tab_free(tab);
+       isl_basic_set_free(bset);
+       isl_vec_free(sol);
+       return NULL;
+}
+
+/* Return the lexicographically smallest rational point in "bset",
+ * assuming that all variables are non-negative.
+ * If "bset" is empty, then return a zero-length vector.
+ */
+ __isl_give isl_vec *isl_tab_basic_set_non_neg_lexmin(
+       __isl_take isl_basic_set *bset)
+{
+       struct isl_tab *tab;
+       isl_ctx *ctx = isl_basic_set_get_ctx(bset);
+       isl_vec *sol;
+
+       tab = tab_for_lexmin(isl_basic_map_from_range(bset), NULL, 0, 0);
+       if (!tab)
+               goto error;
+       if (tab->empty)
+               sol = isl_vec_alloc(ctx, 0);
+       else
+               sol = isl_tab_get_sample_value(tab);
+       isl_tab_free(tab);
+       isl_basic_set_free(bset);
+       return sol;
+error:
+       isl_tab_free(tab);
+       isl_basic_set_free(bset);
+       return NULL;
+}
index 01839c3..55a50d5 100644 (file)
@@ -18,6 +18,7 @@
 #include <isl/polynomial.h>
 #include <isl/union_map.h>
 #include <isl_factorization.h>
+#include <isl/schedule.h>
 
 static char *srcdir;
 
@@ -1506,20 +1507,54 @@ void test_dep(struct isl_ctx *ctx)
        isl_flow_free(flow);
 }
 
-void test_sv(struct isl_ctx *ctx)
+int test_sv(isl_ctx *ctx)
 {
        const char *str;
        isl_map *map;
+       isl_union_map *umap;
+       int sv;
 
        str = "[N] -> { [i] -> [f] : 0 <= i <= N and 0 <= i - 10 f <= 9 }";
        map = isl_map_read_from_str(ctx, str, -1);
-       assert(isl_map_is_single_valued(map));
+       sv = isl_map_is_single_valued(map);
        isl_map_free(map);
+       if (sv < 0)
+               return -1;
+       if (!sv)
+               isl_die(ctx, isl_error_internal,
+                       "map not detected as single valued", return -1);
 
        str = "[N] -> { [i] -> [f] : 0 <= i <= N and 0 <= i - 10 f <= 10 }";
        map = isl_map_read_from_str(ctx, str, -1);
-       assert(!isl_map_is_single_valued(map));
+       sv = isl_map_is_single_valued(map);
        isl_map_free(map);
+       if (sv < 0)
+               return -1;
+       if (sv)
+               isl_die(ctx, isl_error_internal,
+                       "map detected as single valued", return -1);
+
+       str = "{ S1[i] -> [i] : 0 <= i <= 9; S2[i] -> [i] : 0 <= i <= 9 }";
+       umap = isl_union_map_read_from_str(ctx, str);
+       sv = isl_union_map_is_single_valued(umap);
+       isl_union_map_free(umap);
+       if (sv < 0)
+               return -1;
+       if (!sv)
+               isl_die(ctx, isl_error_internal,
+                       "map not detected as single valued", return -1);
+
+       str = "{ [i] -> S1[i] : 0 <= i <= 9; [i] -> S2[i] : 0 <= i <= 9 }";
+       umap = isl_union_map_read_from_str(ctx, str);
+       sv = isl_union_map_is_single_valued(umap);
+       isl_union_map_free(umap);
+       if (sv < 0)
+               return -1;
+       if (sv)
+               isl_die(ctx, isl_error_internal,
+                       "map detected as single valued", return -1);
+
+       return 0;
 }
 
 void test_bijective_case(struct isl_ctx *ctx, const char *str, int bijective)
@@ -1768,6 +1803,385 @@ void test_factorize(isl_ctx *ctx)
        isl_factorizer_free(f);
 }
 
+static int check_injective(__isl_take isl_map *map, void *user)
+{
+       int *injective = user;
+
+       *injective = isl_map_is_injective(map);
+       isl_map_free(map);
+
+       if (*injective < 0 || !*injective)
+               return -1;
+
+       return 0;
+}
+
+int test_one_schedule(isl_ctx *ctx, const char *d, const char *w,
+       const char *r, const char *s, int tilable, int parallel)
+{
+       int i;
+       isl_union_set *D;
+       isl_union_map *W, *R, *S;
+       isl_union_map *empty;
+       isl_union_map *dep_raw, *dep_war, *dep_waw, *dep;
+       isl_union_map *validity, *proximity;
+       isl_union_map *schedule;
+       isl_union_map *test;
+       isl_union_set *delta;
+       isl_union_set *domain;
+       isl_set *delta_set;
+       isl_set *slice;
+       isl_set *origin;
+       isl_schedule *sched;
+       int is_nonneg, is_parallel, is_tilable, is_injection, is_complete;
+
+       D = isl_union_set_read_from_str(ctx, d);
+       W = isl_union_map_read_from_str(ctx, w);
+       R = isl_union_map_read_from_str(ctx, r);
+       S = isl_union_map_read_from_str(ctx, s);
+
+       W = isl_union_map_intersect_domain(W, isl_union_set_copy(D));
+       R = isl_union_map_intersect_domain(R, isl_union_set_copy(D));
+
+       empty = isl_union_map_empty(isl_union_map_get_dim(S));
+        isl_union_map_compute_flow(isl_union_map_copy(R),
+                                  isl_union_map_copy(W), empty,
+                                  isl_union_map_copy(S),
+                                  &dep_raw, NULL, NULL, NULL);
+        isl_union_map_compute_flow(isl_union_map_copy(W),
+                                  isl_union_map_copy(W),
+                                  isl_union_map_copy(R),
+                                  isl_union_map_copy(S),
+                                  &dep_waw, &dep_war, NULL, NULL);
+
+       dep = isl_union_map_union(dep_waw, dep_war);
+       dep = isl_union_map_union(dep, dep_raw);
+       validity = isl_union_map_copy(dep);
+       proximity = isl_union_map_copy(dep);
+
+       sched = isl_union_set_compute_schedule(isl_union_set_copy(D),
+                                              validity, proximity);
+       schedule = isl_schedule_get_map(sched);
+       isl_schedule_free(sched);
+       isl_union_map_free(W);
+       isl_union_map_free(R);
+       isl_union_map_free(S);
+
+       is_injection = 1;
+       isl_union_map_foreach_map(schedule, &check_injective, &is_injection);
+
+       domain = isl_union_map_domain(isl_union_map_copy(schedule));
+       is_complete = isl_union_set_is_subset(D, domain);
+       isl_union_set_free(D);
+       isl_union_set_free(domain);
+
+       test = isl_union_map_reverse(isl_union_map_copy(schedule));
+       test = isl_union_map_apply_range(test, dep);
+       test = isl_union_map_apply_range(test, schedule);
+
+       delta = isl_union_map_deltas(test);
+       if (isl_union_set_n_set(delta) == 0) {
+               is_tilable = 1;
+               is_parallel = 1;
+               is_nonneg = 1;
+       } else {
+               delta_set = isl_union_set_copy_set(delta);
+
+               slice = isl_set_universe(isl_set_get_dim(delta_set));
+               for (i = 0; i < tilable; ++i)
+                       slice = isl_set_lower_bound_si(slice, isl_dim_set, i, 0);
+               is_tilable = isl_set_is_subset(delta_set, slice);
+               isl_set_free(slice);
+
+               slice = isl_set_universe(isl_set_get_dim(delta_set));
+               for (i = 0; i < parallel; ++i)
+                       slice = isl_set_fix_si(slice, isl_dim_set, i, 0);
+               is_parallel = isl_set_is_subset(delta_set, slice);
+               isl_set_free(slice);
+
+               origin = isl_set_universe(isl_set_get_dim(delta_set));
+               for (i = 0; i < isl_set_dim(origin, isl_dim_set); ++i)
+                       origin = isl_set_fix_si(origin, isl_dim_set, i, 0);
+
+               delta_set = isl_set_union(delta_set, isl_set_copy(origin));
+               delta_set = isl_set_lexmin(delta_set);
+
+               is_nonneg = isl_set_is_equal(delta_set, origin);
+
+               isl_set_free(origin);
+               isl_set_free(delta_set);
+       }
+       isl_union_set_free(delta);
+
+       if (is_nonneg < 0 || is_parallel < 0 || is_tilable < 0 ||
+           is_injection < 0 || is_complete < 0)
+               return -1;
+       if (!is_complete)
+               isl_die(ctx, isl_error_unknown,
+                       "generated schedule incomplete", return -1);
+       if (!is_injection)
+               isl_die(ctx, isl_error_unknown,
+                       "generated schedule not injective on each statement",
+                       return -1);
+       if (!is_nonneg)
+               isl_die(ctx, isl_error_unknown,
+                       "negative dependences in generated schedule",
+                       return -1);
+       if (!is_tilable)
+               isl_die(ctx, isl_error_unknown,
+                       "generated schedule not as tilable as expected",
+                       return -1);
+       if (!is_parallel)
+               isl_die(ctx, isl_error_unknown,
+                       "generated schedule not as parallel as expected",
+                       return -1);
+
+       return 0;
+}
+
+int test_special_schedule(isl_ctx *ctx)
+{
+       const char *str;
+       isl_union_set *dom;
+       isl_union_map *empty;
+       isl_union_map *dep;
+       isl_union_map *sched1, *sched2;
+       isl_schedule *schedule;
+       int equal;
+
+       str = "{ S[i,j] : 0 <= i <= 10 }";
+       dom = isl_union_set_read_from_str(ctx, str);
+       str = "{ S[i,j] -> S[i+1,j] : 0 <= i,j <= 10 }";
+       dep = isl_union_map_read_from_str(ctx, str);
+       empty = isl_union_map_read_from_str(ctx, "{}");
+       schedule = isl_union_set_compute_schedule(dom, empty, dep);
+       sched1 = isl_schedule_get_map(schedule);
+       isl_schedule_free(schedule);
+
+       str = "{ S[i, j] -> [j, i] }";
+       sched2 = isl_union_map_read_from_str(ctx, str);
+
+       equal = isl_union_map_is_equal(sched1, sched2);
+       isl_union_map_free(sched1);
+       isl_union_map_free(sched2);
+
+       if (equal < 0)
+               return -1;
+       if (!equal)
+               isl_die(ctx, isl_error_unknown, "unexpected schedule",
+                       return -1);
+
+       return 0;
+}
+
+int test_schedule(isl_ctx *ctx)
+{
+       const char *D, *W, *R, *S;
+
+       /* Jacobi */
+       D = "[T,N] -> { S1[t,i] : 1 <= t <= T and 2 <= i <= N - 1 }";
+       W = "{ S1[t,i] -> a[t,i] }";
+       R = "{ S1[t,i] -> a[t-1,i]; S1[t,i] -> a[t-1,i-1]; "
+               "S1[t,i] -> a[t-1,i+1] }";
+       S = "{ S1[t,i] -> [t,i] }";
+       if (test_one_schedule(ctx, D, W, R, S, 2, 0) < 0)
+               return -1;
+
+       /* Fig. 5 of CC2008 */
+       D = "[N] -> { S_0[i, j] : i >= 0 and i <= -1 + N and j >= 2 and "
+                               "j <= -1 + N }";
+       W = "[N] -> { S_0[i, j] -> a[i, j] : i >= 0 and i <= -1 + N and "
+                               "j >= 2 and j <= -1 + N }";
+       R = "[N] -> { S_0[i, j] -> a[j, i] : i >= 0 and i <= -1 + N and "
+                               "j >= 2 and j <= -1 + N; "
+                   "S_0[i, j] -> a[i, -1 + j] : i >= 0 and i <= -1 + N and "
+                               "j >= 2 and j <= -1 + N }";
+       S = "[N] -> { S_0[i, j] -> [0, i, 0, j, 0] }";
+       if (test_one_schedule(ctx, D, W, R, S, 2, 0) < 0)
+               return -1;
+
+       D = "{ S1[i] : 0 <= i <= 10; S2[i] : 0 <= i <= 9 }";
+       W = "{ S1[i] -> a[i] }";
+       R = "{ S2[i] -> a[i+1] }";
+       S = "{ S1[i] -> [0,i]; S2[i] -> [1,i] }";
+       if (test_one_schedule(ctx, D, W, R, S, 1, 1) < 0)
+               return -1;
+
+       D = "{ S1[i] : 0 <= i < 10; S2[i] : 0 <= i < 10 }";
+       W = "{ S1[i] -> a[i] }";
+       R = "{ S2[i] -> a[9-i] }";
+       S = "{ S1[i] -> [0,i]; S2[i] -> [1,i] }";
+       if (test_one_schedule(ctx, D, W, R, S, 1, 1) < 0)
+               return -1;
+
+       D = "[N] -> { S1[i] : 0 <= i < N; S2[i] : 0 <= i < N }";
+       W = "{ S1[i] -> a[i] }";
+       R = "[N] -> { S2[i] -> a[N-1-i] }";
+       S = "{ S1[i] -> [0,i]; S2[i] -> [1,i] }";
+       if (test_one_schedule(ctx, D, W, R, S, 1, 1) < 0)
+               return -1;
+       
+       D = "{ S1[i] : 0 < i < 10; S2[i] : 0 <= i < 10 }";
+       W = "{ S1[i] -> a[i]; S2[i] -> b[i] }";
+       R = "{ S2[i] -> a[i]; S1[i] -> b[i-1] }";
+       S = "{ S1[i] -> [i,0]; S2[i] -> [i,1] }";
+       if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0)
+               return -1;
+
+       D = "[N] -> { S1[i] : 1 <= i <= N; S2[i,j] : 1 <= i,j <= N }";
+       W = "{ S1[i] -> a[0,i]; S2[i,j] -> a[i,j] }";
+       R = "{ S2[i,j] -> a[i-1,j] }";
+       S = "{ S1[i] -> [0,i,0]; S2[i,j] -> [1,i,j] }";
+       if (test_one_schedule(ctx, D, W, R, S, 2, 1) < 0)
+               return -1;
+
+       D = "[N] -> { S1[i] : 1 <= i <= N; S2[i,j] : 1 <= i,j <= N }";
+       W = "{ S1[i] -> a[i,0]; S2[i,j] -> a[i,j] }";
+       R = "{ S2[i,j] -> a[i,j-1] }";
+       S = "{ S1[i] -> [0,i,0]; S2[i,j] -> [1,i,j] }";
+       if (test_one_schedule(ctx, D, W, R, S, 2, 1) < 0)
+               return -1;
+
+       D = "[N] -> { S_0[]; S_1[i] : i >= 0 and i <= -1 + N; S_2[] }";
+       W = "[N] -> { S_0[] -> a[0]; S_2[] -> b[0]; "
+                   "S_1[i] -> a[1 + i] : i >= 0 and i <= -1 + N }";
+       R = "[N] -> { S_2[] -> a[N]; S_1[i] -> a[i] : i >= 0 and i <= -1 + N }";
+       S = "[N] -> { S_1[i] -> [1, i, 0]; S_2[] -> [2, 0, 1]; "
+                   "S_0[] -> [0, 0, 0] }";
+       if (test_one_schedule(ctx, D, W, R, S, 1, 0) < 0)
+               return -1;
+       ctx->opt->schedule_parametric = 0;
+       if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0)
+               return -1;
+       ctx->opt->schedule_parametric = 1;
+
+       D = "[N] -> { S1[i] : 1 <= i <= N; S2[i] : 1 <= i <= N; "
+                   "S3[i,j] : 1 <= i,j <= N; S4[i] : 1 <= i <= N }";
+       W = "{ S1[i] -> a[i,0]; S2[i] -> a[0,i]; S3[i,j] -> a[i,j] }";
+       R = "[N] -> { S3[i,j] -> a[i-1,j]; S3[i,j] -> a[i,j-1]; "
+                   "S4[i] -> a[i,N] }";
+       S = "{ S1[i] -> [0,i,0]; S2[i] -> [1,i,0]; S3[i,j] -> [2,i,j]; "
+               "S4[i] -> [4,i,0] }";
+       if (test_one_schedule(ctx, D, W, R, S, 2, 0) < 0)
+               return -1;
+
+       D = "[N] -> { S_0[i, j] : i >= 1 and i <= N and j >= 1 and j <= N }";
+       W = "[N] -> { S_0[i, j] -> s[0] : i >= 1 and i <= N and j >= 1 and "
+                                       "j <= N }";
+       R = "[N] -> { S_0[i, j] -> s[0] : i >= 1 and i <= N and j >= 1 and "
+                                       "j <= N; "
+                   "S_0[i, j] -> a[i, j] : i >= 1 and i <= N and j >= 1 and "
+                                       "j <= N }";
+       S = "[N] -> { S_0[i, j] -> [0, i, 0, j, 0] }";
+       if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0)
+               return -1;
+
+       D = "[N] -> { S_0[t] : t >= 0 and t <= -1 + N; "
+                   " S_2[t] : t >= 0 and t <= -1 + N; "
+                   " S_1[t, i] : t >= 0 and t <= -1 + N and i >= 0 and "
+                               "i <= -1 + N }";
+       W = "[N] -> { S_0[t] -> a[t, 0] : t >= 0 and t <= -1 + N; "
+                   " S_2[t] -> b[t] : t >= 0 and t <= -1 + N; "
+                   " S_1[t, i] -> a[t, 1 + i] : t >= 0 and t <= -1 + N and "
+                                               "i >= 0 and i <= -1 + N }";
+       R = "[N] -> { S_1[t, i] -> a[t, i] : t >= 0 and t <= -1 + N and "
+                                           "i >= 0 and i <= -1 + N; "
+                   " S_2[t] -> a[t, N] : t >= 0 and t <= -1 + N }";
+       S = "[N] -> { S_2[t] -> [0, t, 2]; S_1[t, i] -> [0, t, 1, i, 0]; "
+                   " S_0[t] -> [0, t, 0] }";
+
+       if (test_one_schedule(ctx, D, W, R, S, 2, 1) < 0)
+               return -1;
+       ctx->opt->schedule_parametric = 0;
+       if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0)
+               return -1;
+       ctx->opt->schedule_parametric = 1;
+
+       D = "[N] -> { S1[i,j] : 0 <= i,j < N; S2[i,j] : 0 <= i,j < N }";
+       S = "{ S1[i,j] -> [0,i,j]; S2[i,j] -> [1,i,j] }";
+       if (test_one_schedule(ctx, D, "{}", "{}", S, 2, 2) < 0)
+               return -1;
+
+       D = "[M, N] -> { S_1[i] : i >= 0 and i <= -1 + M; "
+           "S_0[i, j] : i >= 0 and i <= -1 + M and j >= 0 and j <= -1 + N }";
+       W = "[M, N] -> { S_0[i, j] -> a[j] : i >= 0 and i <= -1 + M and "
+                                           "j >= 0 and j <= -1 + N; "
+                       "S_1[i] -> b[0] : i >= 0 and i <= -1 + M }";
+       R = "[M, N] -> { S_0[i, j] -> a[0] : i >= 0 and i <= -1 + M and "
+                                           "j >= 0 and j <= -1 + N; "
+                       "S_1[i] -> b[0] : i >= 0 and i <= -1 + M }";
+       S = "[M, N] -> { S_1[i] -> [1, i, 0]; S_0[i, j] -> [0, i, 0, j, 0] }";
+       if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0)
+               return -1;
+
+       D = "{ S_0[i] : i >= 0 }";
+       W = "{ S_0[i] -> a[i] : i >= 0 }";
+       R = "{ S_0[i] -> a[0] : i >= 0 }";
+       S = "{ S_0[i] -> [0, i, 0] }";
+       if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0)
+               return -1;
+
+       D = "{ S_0[i] : i >= 0; S_1[i] : i >= 0 }";
+       W = "{ S_0[i] -> a[i] : i >= 0; S_1[i] -> b[i] : i >= 0 }";
+       R = "{ S_0[i] -> b[0] : i >= 0; S_1[i] -> a[i] : i >= 0 }";
+       S = "{ S_1[i] -> [0, i, 1]; S_0[i] -> [0, i, 0] }";
+       if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0)
+               return -1;
+
+       return test_special_schedule(ctx);
+}
+
+int test_plain_injective(isl_ctx *ctx, const char *str, int injective)
+{
+       isl_union_map *umap;
+       int test;
+
+       umap = isl_union_map_read_from_str(ctx, str);
+       test = isl_union_map_plain_is_injective(umap);
+       isl_union_map_free(umap);
+       if (test < 0)
+               return -1;
+       if (test == injective)
+               return 0;
+       if (injective)
+               isl_die(ctx, isl_error_unknown,
+                       "map not detected as injective", return -1);
+       else
+               isl_die(ctx, isl_error_unknown,
+                       "map detected as injective", return -1);
+}
+
+int test_injective(isl_ctx *ctx)
+{
+       const char *str;
+
+       if (test_plain_injective(ctx, "{S[i,j] -> A[0]; T[i,j] -> B[1]}", 0))
+               return -1;
+       if (test_plain_injective(ctx, "{S[] -> A[0]; T[] -> B[0]}", 1))
+               return -1;
+       if (test_plain_injective(ctx, "{S[] -> A[0]; T[] -> A[1]}", 1))
+               return -1;
+       if (test_plain_injective(ctx, "{S[] -> A[0]; T[] -> A[0]}", 0))
+               return -1;
+       if (test_plain_injective(ctx, "{S[i] -> A[i,0]; T[i] -> A[i,1]}", 1))
+               return -1;
+       if (test_plain_injective(ctx, "{S[i] -> A[i]; T[i] -> A[i]}", 0))
+               return -1;
+       if (test_plain_injective(ctx, "{S[] -> A[0,0]; T[] -> A[0,1]}", 1))
+               return -1;
+       if (test_plain_injective(ctx, "{S[] -> A[0,0]; T[] -> A[1,0]}", 1))
+               return -1;
+
+       str = "{S[] -> A[0,0]; T[] -> A[0,1]; U[] -> A[1,0]}";
+       if (test_plain_injective(ctx, str, 1))
+               return -1;
+       str = "{S[] -> A[0,0]; T[] -> A[0,1]; U[] -> A[0,0]}";
+       if (test_plain_injective(ctx, str, 0))
+               return -1;
+
+       return 0;
+}
+
 int main()
 {
        struct isl_ctx *ctx;
@@ -1776,6 +2190,10 @@ int main()
        assert(srcdir);
 
        ctx = isl_ctx_alloc();
+       if (test_injective(ctx) < 0)
+               goto error;
+       if (test_schedule(ctx) < 0)
+               goto error;
        test_factorize(ctx);
        test_subset(ctx);
        test_lift(ctx);
@@ -1785,7 +2203,8 @@ int main()
        test_parse(ctx);
        test_pwqp(ctx);
        test_lex(ctx);
-       test_sv(ctx);
+       if (test_sv(ctx) < 0)
+               goto error;
        test_bijective(ctx);
        test_dep(ctx);
        test_read(ctx);
@@ -1802,4 +2221,7 @@ int main()
        test_lexmin(ctx);
        isl_ctx_free(ctx);
        return 0;
+error:
+       isl_ctx_free(ctx);
+       return -1;
 }
index 629eb74..d72c0c7 100644 (file)
@@ -769,7 +769,7 @@ static __isl_give isl_map *construct_extended_path(__isl_take isl_dim *dim,
                for (j = 0; j < d; ++j) {
                        int fixed;
 
-                       fixed = isl_basic_set_fast_dim_is_fixed(delta, j,
+                       fixed = isl_basic_set_plain_dim_is_fixed(delta, j,
                                                            &steps->row[n][j]);
                        if (fixed < 0) {
                                isl_basic_set_free(delta);
@@ -2161,7 +2161,7 @@ __isl_give isl_map *isl_map_power(__isl_take isl_map *map, int *exact)
        map = isl_map_compute_divs(map);
        map = isl_map_coalesce(map);
 
-       if (isl_map_fast_is_empty(map)) {
+       if (isl_map_plain_is_empty(map)) {
                map = isl_map_from_range(isl_map_wrap(map));
                map = isl_map_add_dims(map, isl_dim_in, 1);
                map = isl_map_set_dim_name(map, isl_dim_in, 0, "k");
@@ -2215,7 +2215,7 @@ __isl_give isl_map *isl_map_reaching_path_lengths(__isl_take isl_map *map,
        map = isl_map_compute_divs(map);
        map = isl_map_coalesce(map);
 
-       if (isl_map_fast_is_empty(map)) {
+       if (isl_map_plain_is_empty(map)) {
                if (exact)
                        *exact = 1;
                map = isl_map_project_out(map, isl_dim_out, 0, d);
index c2ba975..7da5141 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010      INRIA Saclay
+ * Copyright 2010-2011 INRIA Saclay
  *
  * Use of this software is governed by the GNU LGPLv2.1 license
  *
@@ -259,7 +259,7 @@ __isl_give isl_union_map *isl_union_map_add_map(__isl_take isl_union_map *umap,
        uint32_t hash;
        struct isl_hash_table_entry *entry;
 
-       if (isl_map_fast_is_empty(map)) {
+       if (isl_map_plain_is_empty(map)) {
                isl_map_free(map);
                return umap;
        }
@@ -359,6 +359,33 @@ int isl_union_map_foreach_map(__isl_keep isl_union_map *umap,
                                      &call_on_copy, &data);
 }
 
+static int copy_map(void **entry, void *user)
+{
+       isl_map *map = *entry;
+       isl_map **map_p = user;
+
+       *map_p = isl_map_copy(map);
+
+       return -1;
+}
+
+__isl_give isl_map *isl_union_map_copy_map(__isl_keep isl_union_map *umap)
+{
+       isl_map *map = NULL;
+
+       if (!umap || umap->table.n == 0)
+               return NULL;
+
+       isl_hash_table_foreach(umap->dim->ctx, &umap->table, &copy_map, &map);
+
+       return map;
+}
+
+__isl_give isl_set *isl_union_set_copy_set(__isl_keep isl_union_set *uset)
+{
+       return isl_union_map_copy_map(uset);
+}
+
 __isl_give isl_map *isl_union_map_extract_map(__isl_keep isl_union_map *umap,
        __isl_take isl_dim *dim)
 {
@@ -386,6 +413,29 @@ __isl_give isl_set *isl_union_set_extract_set(__isl_keep isl_union_set *uset,
        return (isl_set *)isl_union_map_extract_map(uset, dim);
 }
 
+/* Check if umap contains a map in the given space.
+ */
+__isl_give int isl_union_map_contains(__isl_keep isl_union_map *umap,
+       __isl_keep isl_dim *dim)
+{
+       uint32_t hash;
+       struct isl_hash_table_entry *entry;
+
+       if (!umap || !dim)
+               return -1;
+
+       hash = isl_dim_get_hash(dim);
+       entry = isl_hash_table_find(umap->dim->ctx, &umap->table, hash,
+                                   &has_dim, dim, 0);
+       return !!entry;
+}
+
+__isl_give int isl_union_set_contains(__isl_keep isl_union_set *uset,
+       __isl_keep isl_dim *dim)
+{
+       return isl_union_map_contains(uset, dim);
+}
+
 int isl_union_set_foreach_set(__isl_keep isl_union_set *uset,
        int (*fn)(__isl_take isl_set *set, void *user), void *user)
 {
@@ -1125,6 +1175,27 @@ error:
        return NULL;
 }
 
+static int universe_entry(void **entry, void *user)
+{
+       isl_map *map = *entry;
+       isl_union_map **res = user;
+
+       map = isl_map_universe(isl_map_get_dim(map));
+       *res = isl_union_map_add_map(*res, map);
+
+       return 0;
+}
+
+__isl_give isl_union_map *isl_union_map_universe(__isl_take isl_union_map *umap)
+{
+       return cond_un_op(umap, &universe_entry);
+}
+
+__isl_give isl_union_set *isl_union_set_universe(__isl_take isl_union_set *uset)
+{
+       return isl_union_map_universe(uset);
+}
+
 static int reverse_entry(void **entry, void *user)
 {
        isl_map *map = *entry;
@@ -1402,7 +1473,7 @@ static int sample_entry(void **entry, void *user)
        *sample = isl_map_sample(isl_map_copy(map));
        if (!*sample)
                return -1;
-       if (!isl_basic_map_fast_is_empty(*sample))
+       if (!isl_basic_map_plain_is_empty(*sample))
                return -1;
        return 0;
 }
@@ -1435,31 +1506,82 @@ __isl_give isl_basic_set *isl_union_set_sample(__isl_take isl_union_set *uset)
        return (isl_basic_set *)isl_union_map_sample(uset);
 }
 
-static int empty_entry(void **entry, void *user)
+struct isl_forall_data {
+       int res;
+       int (*fn)(__isl_keep isl_map *map);
+};
+
+static int forall_entry(void **entry, void *user)
 {
-       int *empty = user;
+       struct isl_forall_data *data = user;
        isl_map *map = *entry;
 
-       if (isl_map_is_empty(map))
-               return 0;
+       data->res = data->fn(map);
+       if (data->res < 0)
+               return -1;
+
+       if (!data->res)
+               return -1;
 
-       *empty = 0;
+       return 0;
+}
 
-       return -1;
+static int union_map_forall(__isl_keep isl_union_map *umap,
+       int (*fn)(__isl_keep isl_map *map))
+{
+       struct isl_forall_data data = { 1, fn };
+
+       if (!umap)
+               return -1;
+
+       if (isl_hash_table_foreach(umap->dim->ctx, &umap->table,
+                                  &forall_entry, &data) < 0 && data.res)
+               return -1;
+
+       return data.res;
+}
+
+struct isl_forall_user_data {
+       int res;
+       int (*fn)(__isl_keep isl_map *map, void *user);
+       void *user;
+};
+
+static int forall_user_entry(void **entry, void *user)
+{
+       struct isl_forall_user_data *data = user;
+       isl_map *map = *entry;
+
+       data->res = data->fn(map, data->user);
+       if (data->res < 0)
+               return -1;
+
+       if (!data->res)
+               return -1;
+
+       return 0;
 }
 
-__isl_give int isl_union_map_is_empty(__isl_keep isl_union_map *umap)
+/* Check if fn(map, user) returns true for all maps "map" in umap.
+ */
+static int union_map_forall_user(__isl_keep isl_union_map *umap,
+       int (*fn)(__isl_keep isl_map *map, void *user), void *user)
 {
-       int empty = 1;
+       struct isl_forall_user_data data = { 1, fn, user };
 
        if (!umap)
                return -1;
 
        if (isl_hash_table_foreach(umap->dim->ctx, &umap->table,
-                                  &empty_entry, &empty) < 0 && empty)
+                                  &forall_user_entry, &data) < 0 && data.res)
                return -1;
 
-       return empty;
+       return data.res;
+}
+
+int isl_union_map_is_empty(__isl_keep isl_union_map *umap)
+{
+       return union_map_forall(umap, &isl_map_is_empty);
 }
 
 int isl_union_set_is_empty(__isl_keep isl_union_set *uset)
@@ -1467,6 +1589,306 @@ int isl_union_set_is_empty(__isl_keep isl_union_set *uset)
        return isl_union_map_is_empty(uset);
 }
 
+static int is_subset_of_identity(__isl_keep isl_map *map)
+{
+       int is_subset;
+       isl_dim *dim;
+       isl_map *id;
+
+       if (!map)
+               return -1;
+
+       if (!isl_dim_tuple_match(map->dim, isl_dim_in, map->dim, isl_dim_out))
+               return 0;
+
+       dim = isl_map_get_dim(map);
+       id = isl_map_identity(dim);
+
+       is_subset = isl_map_is_subset(map, id);
+
+       isl_map_free(id);
+
+       return is_subset;
+}
+
+/* Check if the given map is single-valued.
+ * We simply compute
+ *
+ *     M \circ M^-1
+ *
+ * and check if the result is a subset of the identity mapping.
+ */
+int isl_union_map_is_single_valued(__isl_keep isl_union_map *umap)
+{
+       isl_union_map *test;
+       int sv;
+
+       if (isl_union_map_n_map(umap) == 1) {
+               isl_map *map = isl_union_map_copy_map(umap);
+               sv = isl_map_is_single_valued(map);
+               isl_map_free(map);
+               return sv;
+       }
+
+       test = isl_union_map_reverse(isl_union_map_copy(umap));
+       test = isl_union_map_apply_range(test, isl_union_map_copy(umap));
+
+       sv = union_map_forall(test, &is_subset_of_identity);
+
+       isl_union_map_free(test);
+
+       return sv;
+}
+
+int isl_union_map_is_injective(__isl_keep isl_union_map *umap)
+{
+       int in;
+
+       umap = isl_union_map_copy(umap);
+       umap = isl_union_map_reverse(umap);
+       in = isl_union_map_is_single_valued(umap);
+       isl_union_map_free(umap);
+
+       return in;
+}
+
+/* Represents a map that has a fixed value (v) for one of its
+ * range dimensions.
+ * The map in this structure is not reference counted, so it
+ * is only valid while the isl_union_map from which it was
+ * obtained is still alive.
+ */
+struct isl_fixed_map {
+       isl_int v;
+       isl_map *map;
+};
+
+static struct isl_fixed_map *alloc_isl_fixed_map_array(isl_ctx *ctx,
+       int n)
+{
+       int i;
+       struct isl_fixed_map *v;
+
+       v = isl_calloc_array(ctx, struct isl_fixed_map, n);
+       if (!v)
+               return NULL;
+       for (i = 0; i < n; ++i)
+               isl_int_init(v[i].v);
+       return v;
+}
+
+static void free_isl_fixed_map_array(struct isl_fixed_map *v, int n)
+{
+       int i;
+
+       if (!v)
+               return;
+       for (i = 0; i < n; ++i)
+               isl_int_clear(v[i].v);
+       free(v);
+}
+
+/* Compare the "v" field of two isl_fixed_map structs.
+ */
+static int qsort_fixed_map_cmp(const void *p1, const void *p2)
+{
+       const struct isl_fixed_map *e1 = (const struct isl_fixed_map *) p1;
+       const struct isl_fixed_map *e2 = (const struct isl_fixed_map *) p2;
+
+       return isl_int_cmp(e1->v, e2->v);
+}
+
+/* Internal data structure used while checking whether all maps
+ * in a union_map have a fixed value for a given output dimension.
+ * v is the list of maps, with the fixed value for the dimension
+ * n is the number of maps considered so far
+ * pos is the output dimension under investigation
+ */
+struct isl_fixed_dim_data {
+       struct isl_fixed_map *v;
+       int n;
+       int pos;
+};
+
+static int fixed_at_pos(__isl_keep isl_map *map, void *user)
+{
+       struct isl_fixed_dim_data *data = user;
+
+       data->v[data->n].map = map;
+       return isl_map_plain_is_fixed(map, isl_dim_out, data->pos,
+                                     &data->v[data->n++].v);
+}
+
+static int plain_injective_on_range(__isl_take isl_union_map *umap,
+       int first, int n_range);
+
+/* Given a list of the maps, with their fixed values at output dimension "pos",
+ * check whether the ranges of the maps form an obvious partition.
+ *
+ * We first sort the maps according to their fixed values.
+ * If all maps have a different value, then we know the ranges form
+ * a partition.
+ * Otherwise, we collect the maps with the same fixed value and
+ * check whether each such collection is obviously injective
+ * based on later dimensions.
+ */
+static int separates(struct isl_fixed_map *v, int n,
+       __isl_take isl_dim *dim, int pos, int n_range)
+{
+       int i;
+
+       if (!v)
+               goto error;
+
+       qsort(v, n, sizeof(*v), &qsort_fixed_map_cmp);
+
+       for (i = 0; i + 1 < n; ++i) {
+               int j, k;
+               isl_union_map *part;
+               int injective;
+
+               for (j = i + 1; j < n; ++j)
+                       if (isl_int_ne(v[i].v, v[j].v))
+                               break;
+
+               if (j == i + 1)
+                       continue;
+
+               part = isl_union_map_alloc(isl_dim_copy(dim), j - i);
+               for (k = i; k < j; ++k)
+                       part = isl_union_map_add_map(part,
+                                                    isl_map_copy(v[k].map));
+
+               injective = plain_injective_on_range(part, pos + 1, n_range);
+               if (injective < 0)
+                       goto error;
+               if (!injective)
+                       break;
+
+               i = j - 1;
+       }
+
+       isl_dim_free(dim);
+       free_isl_fixed_map_array(v, n);
+       return i + 1 >= n;
+error:
+       isl_dim_free(dim);
+       free_isl_fixed_map_array(v, n);
+       return -1;
+}
+
+/* Check whether the maps in umap have obviously distinct ranges.
+ * In particular, check for an output dimension in the range
+ * [first,n_range) for which all maps have a fixed value
+ * and then check if these values, possibly along with fixed values
+ * at later dimensions, entail distinct ranges.
+ */
+static int plain_injective_on_range(__isl_take isl_union_map *umap,
+       int first, int n_range)
+{
+       isl_ctx *ctx;
+       int n;
+       struct isl_fixed_dim_data data = { NULL };
+
+       ctx = isl_union_map_get_ctx(umap);
+
+       if (!umap)
+               goto error;
+
+       n = isl_union_map_n_map(umap);
+       if (n <= 1) {
+               isl_union_map_free(umap);
+               return 1;
+       }
+
+       if (first >= n_range) {
+               isl_union_map_free(umap);
+               return 0;
+       }
+
+       data.v = alloc_isl_fixed_map_array(ctx, n);
+       if (!data.v)
+               goto error;
+
+       for (data.pos = first; data.pos < n_range; ++data.pos) {
+               int fixed;
+               int injective;
+               isl_dim *dim;
+
+               data.n = 0;
+               fixed = union_map_forall_user(umap, &fixed_at_pos, &data);
+               if (fixed < 0)
+                       goto error;
+               if (!fixed)
+                       continue;
+               dim = isl_union_map_get_dim(umap);
+               injective = separates(data.v, n, dim, data.pos, n_range);
+               isl_union_map_free(umap);
+               return injective;
+       }
+
+       free_isl_fixed_map_array(data.v, n);
+       isl_union_map_free(umap);
+
+       return 0;
+error:
+       free_isl_fixed_map_array(data.v, n);
+       isl_union_map_free(umap);
+       return -1;
+}
+
+/* Check whether the maps in umap that map to subsets of "ran"
+ * have obviously distinct ranges.
+ */
+static int plain_injective_on_range_wrap(__isl_keep isl_set *ran, void *user)
+{
+       isl_union_map *umap = user;
+
+       umap = isl_union_map_copy(umap);
+       umap = isl_union_map_intersect_range(umap,
+                       isl_union_set_from_set(isl_set_copy(ran)));
+       return plain_injective_on_range(umap, 0, isl_set_dim(ran, isl_dim_set));
+}
+
+/* Check if the given union_map is obviously injective.
+ *
+ * In particular, we first check if all individual maps are obviously
+ * injective and then check if all the ranges of these maps are
+ * obviously disjoint.
+ */
+int isl_union_map_plain_is_injective(__isl_keep isl_union_map *umap)
+{
+       int in;
+       isl_union_map *univ;
+       isl_union_set *ran;
+
+       in = union_map_forall(umap, &isl_map_plain_is_injective);
+       if (in < 0)
+               return -1;
+       if (!in)
+               return 0;
+
+       univ = isl_union_map_universe(isl_union_map_copy(umap));
+       ran = isl_union_map_range(univ);
+
+       in = union_map_forall_user(ran, &plain_injective_on_range_wrap, umap);
+
+       isl_union_set_free(ran);
+
+       return in;
+}
+
+int isl_union_map_is_bijective(__isl_keep isl_union_map *umap)
+{
+       int sv;
+
+       sv = isl_union_map_is_single_valued(umap);
+       if (sv < 0 || !sv)
+               return sv;
+
+       return isl_union_map_is_injective(umap);
+}
+
 static int zip_entry(void **entry, void *user)
 {
        isl_map *map = *entry;
@@ -1484,3 +1906,101 @@ __isl_give isl_union_map *isl_union_map_zip(__isl_take isl_union_map *umap)
 {
        return cond_un_op(umap, &zip_entry);
 }
+
+static int lift_entry(void **entry, void *user)
+{
+       isl_set *set = *entry;
+       isl_union_set **res = user;
+
+       *res = isl_union_set_add_set(*res, isl_set_lift(isl_set_copy(set)));
+
+       return 0;
+}
+
+__isl_give isl_union_set *isl_union_set_lift(__isl_take isl_union_set *uset)
+{
+       return cond_un_op(uset, &lift_entry);
+}
+
+static int coefficients_entry(void **entry, void *user)
+{
+       isl_set *set = *entry;
+       isl_union_set **res = user;
+
+       set = isl_set_copy(set);
+       set = isl_set_from_basic_set(isl_set_coefficients(set));
+       *res = isl_union_set_add_set(*res, set);
+
+       return 0;
+}
+
+__isl_give isl_union_set *isl_union_set_coefficients(
+       __isl_take isl_union_set *uset)
+{
+       isl_ctx *ctx;
+       isl_dim *dim;
+       isl_union_set *res;
+
+       if (!uset)
+               return NULL;
+
+       ctx = isl_union_set_get_ctx(uset);
+       dim = isl_dim_set_alloc(ctx, 0, 0);
+       res = isl_union_map_alloc(dim, uset->table.n);
+       if (isl_hash_table_foreach(uset->dim->ctx, &uset->table,
+                                  &coefficients_entry, &res) < 0)
+               goto error;
+
+       isl_union_set_free(uset);
+       return res;
+error:
+       isl_union_set_free(uset);
+       isl_union_set_free(res);
+       return NULL;
+}
+
+static int solutions_entry(void **entry, void *user)
+{
+       isl_set *set = *entry;
+       isl_union_set **res = user;
+
+       set = isl_set_copy(set);
+       set = isl_set_from_basic_set(isl_set_solutions(set));
+       if (!*res)
+               *res = isl_union_set_from_set(set);
+       else
+               *res = isl_union_set_add_set(*res, set);
+
+       if (!*res)
+               return -1;
+
+       return 0;
+}
+
+__isl_give isl_union_set *isl_union_set_solutions(
+       __isl_take isl_union_set *uset)
+{
+       isl_ctx *ctx;
+       isl_dim *dim;
+       isl_union_set *res = NULL;
+
+       if (!uset)
+               return NULL;
+
+       if (uset->table.n == 0) {
+               res = isl_union_set_empty(isl_union_set_get_dim(uset));
+               isl_union_set_free(uset);
+               return res;
+       }
+
+       if (isl_hash_table_foreach(uset->dim->ctx, &uset->table,
+                                  &solutions_entry, &res) < 0)
+               goto error;
+
+       isl_union_set_free(uset);
+       return res;
+error:
+       isl_union_set_free(uset);
+       isl_union_set_free(res);
+       return NULL;
+}
index 2efe123..9df16a2 100644 (file)
--- a/isl_vec.c
+++ b/isl_vec.c
 #include <isl/seq.h>
 #include <isl/vec.h>
 
+isl_ctx *isl_vec_get_ctx(__isl_keep isl_vec *vec)
+{
+       return vec ? vec->ctx : NULL;
+}
+
 struct isl_vec *isl_vec_alloc(struct isl_ctx *ctx, unsigned size)
 {
        struct isl_vec *vec;
@@ -233,3 +238,21 @@ error:
        isl_vec_free(vec2);
        return NULL;
 }
+
+static int qsort_int_cmp(const void *p1, const void *p2)
+{
+       const isl_int *i1 = (const isl_int *) p1;
+       const isl_int *i2 = (const isl_int *) p2;
+
+       return isl_int_cmp(*i1, *i2);
+}
+
+__isl_give isl_vec *isl_vec_sort(__isl_take isl_vec *vec)
+{
+       if (!vec)
+               return NULL;
+       
+       qsort(vec->el, vec->size, sizeof(*vec->el), &qsort_int_cmp);
+
+       return vec;
+}
index 9c98330..1dd0f03 100644 (file)
@@ -403,7 +403,7 @@ __isl_give isl_vertices *isl_basic_set_compute_vertices(
        if (!bset)
                return NULL;
 
-       if (isl_basic_set_fast_is_empty(bset))
+       if (isl_basic_set_plain_is_empty(bset))
                return vertices_empty(bset);
 
        if (bset->n_eq != 0)
@@ -771,7 +771,7 @@ static int has_opposite(struct isl_facet_todo *todo,
 {
        for (; *list; list = &(*list)->next) {
                int eq;
-               eq = isl_basic_set_fast_is_equal(todo->bset, (*list)->bset);
+               eq = isl_basic_set_plain_is_equal(todo->bset, (*list)->bset);
                if (eq < 0)
                        return -1;
                if (!eq)
diff --git a/pip.c b/pip.c
index eed7a3c..7977431 100644 (file)
--- a/pip.c
+++ b/pip.c
@@ -122,7 +122,7 @@ struct isl_vec *opt_at(struct isl_basic_set *bset,
 
        bset = plug_in_parameters(bset, params);
 
-       if (isl_basic_set_fast_is_empty(bset)) {
+       if (isl_basic_set_plain_is_empty(bset)) {
                opt = isl_vec_alloc(bset->ctx, 0);
                isl_basic_set_free(bset);
                return opt;
index 2ccee4f..60ac3e5 100644 (file)
@@ -95,7 +95,7 @@ int main(int argc, char **argv)
 
        bset = isl_basic_set_read_from_file(ctx, stdin, 0);
        samples = isl_basic_set_samples(bset);
-       isl_mat_dump(samples, stdout, 0);
+       isl_mat_print_internal(samples, stdout, 0);
        isl_mat_free(samples);
        isl_ctx_free(ctx);