Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod
91893 Orsay
France
+
+The quicksort implementation was written by Douglas C. Schmidt.
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 \
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 \
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 \
isl_sample.c \
isl_scan.c \
isl_scan.h \
+ isl_schedule.c \
isl_stream.c \
isl_seq.c \
isl_tab.c \
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
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
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 \
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 \
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 \
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}" \
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);
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
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
\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
month = oct,
YEAR = {2006}
}
+
+@misc{DeSmet2010personal,
+ author = "De Smet, Sven",
+ title = "personal communication",
+ year = 2010,
+ month = apr,
+}
\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}
=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
__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);
__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.
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
__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
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(
__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.
__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
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.
__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,
=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);
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(
=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);
__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,
=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
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(
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(
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,
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(
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(
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
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.
__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
__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.
__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);
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
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);
--- /dev/null
+#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
#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" {
};
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,
__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,
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,
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
#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);
#ifndef ISL_ILP_H
#define ISL_ILP_H
+#include <isl/aff.h>
#include <isl/lp.h>
#if defined(__cplusplus)
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)
}
--- /dev/null
+#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
#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" {
__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,
__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,
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,
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);
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,
__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);
__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,
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);
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);
__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);
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)
}
#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)
#include <isl/point.h>
#include <isl/printer.h>
#include <isl/union_set.h>
+#include <isl/aff.h>
#if defined(__cplusplus)
extern "C" {
__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;
__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);
--- /dev/null
+#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
#include <isl/map.h>
#include <isl/list.h>
#include <isl/point.h>
+#include <isl/local_space.h>
#if defined(__cplusplus)
extern "C" {
__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,
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);
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);
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,
__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);
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);
__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);
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);
__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
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(
__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);
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);
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(
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(
__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,
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);
__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)
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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
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);
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;
{
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));
#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;
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;
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))
#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)
{
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)
{
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)
{
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)
{
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;
+}
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);
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;
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;
isl_int_init(ctx->normalize_gcd);
ctx->n_cached = 0;
+ ctx->n_miss = 0;
ctx->error = isl_error_none;
isl_int normalize_gcd;
int n_cached;
+ int n_miss;
struct isl_blk cache[ISL_BLK_CACHE_SIZE];
struct isl_hash_table name_hash;
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;
}
}
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)
{
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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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
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);
*/
#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;
--- /dev/null
+#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;
+};
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)
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);
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;
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;
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)
}
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);
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;
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;
}
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;
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);
--- /dev/null
+/*
+ * 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;
+}
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
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)
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) {
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;
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,
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);
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) {
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;
}
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;
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;
}
--- /dev/null
+#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;
+}
--- /dev/null
+#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
#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
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)
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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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
#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)
{
}
}
-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)
{
}
}
+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);
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)
{
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)
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)
{
(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)
{
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.
*/
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;
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;
}
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;
}
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;
}
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);
}
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);
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;
}
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);
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);
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;
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));
}
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;
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);
{
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;
}
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);
if (!map || !dom)
goto error;
- if (isl_map_fast_is_empty(map)) {
+ if (isl_map_plain_is_empty(map)) {
if (empty)
*empty = dom;
else
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);
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);
if (!set)
return -1;
- if (isl_set_fast_is_empty(set)) {
+ if (isl_set_plain_is_empty(set)) {
isl_set_free(set);
return 0;
}
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);
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);
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;
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)
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);
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.
*
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;
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;
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;
}
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;
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;
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;
(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;
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);
}
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
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)
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;
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;
}
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,
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:
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:
* 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;
/* 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;
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.
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;
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;
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)
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".
*/
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:
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);
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,
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);
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);
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);
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
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)
--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);
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;
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)
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;
}
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;
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) {
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;
}
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);
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];
* 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;
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;
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.
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;
/* 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;
/* 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
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;
#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)
{
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;
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)
{
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;
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;
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;
}
}
+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;
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)
{
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;
+}
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);
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)
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);
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;
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)
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);
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);
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);
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)
}
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)
}
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)
"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
};
#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 " };
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
{
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]);
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,
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);
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)
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)
{
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;
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);
}
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) {
{
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) {
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);
+}
#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)
{
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;
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)
{
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;
*
* 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.
*/
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;
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)
{
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);
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;
}
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)
{
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;
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);
__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);
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;
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;
}
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)
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)
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;
}
--- /dev/null
+/* 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;
+ }
+ }
+ }
+ }
+}
--- /dev/null
+#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
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);
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);
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;
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);
--- /dev/null
+/*
+ * 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;
+}
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;
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);
+}
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;
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);
* 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,
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
* 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
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;
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;
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,
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)
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;
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);
static void find_solutions(struct isl_sol *sol, struct isl_tab *tab)
{
struct isl_context *context;
+ int r;
if (!tab || sol->error)
goto error;
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;
if (row < 0)
goto error;
}
+ if (r < 0)
+ goto error;
done:
sol_add(sol, tab);
isl_tab_free(tab);
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 {
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);
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;
{
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;
+}
#include <isl/polynomial.h>
#include <isl/union_map.h>
#include <isl_factorization.h>
+#include <isl/schedule.h>
static char *srcdir;
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)
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;
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);
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);
test_lexmin(ctx);
isl_ctx_free(ctx);
return 0;
+error:
+ isl_ctx_free(ctx);
+ return -1;
}
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);
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");
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);
/*
- * Copyright 2010 INRIA Saclay
+ * Copyright 2010-2011 INRIA Saclay
*
* Use of this software is governed by the GNU LGPLv2.1 license
*
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;
}
&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, ©_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)
{
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)
{
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;
*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;
}
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)
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;
{
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;
+}
#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;
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;
+}
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)
{
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)
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;
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);